[Libreoffice-commits] core.git: Branch 'distro/cib/libreoffice-6-4' - 3 commits - external/xmlsec include/xmloff sw/qa sw/source xmlsecurity/source
Michael Stahl (via logerrit)
logerrit at kemper.freedesktop.org
Thu Apr 15 00:50:33 UTC 2021
Rebased ref, commits from common ancestor:
commit c523da10fbdd54b80439e9594e3e5af78f6e955b
Author: Michael Stahl <michael.stahl at allotropia.de>
AuthorDate: Wed Apr 7 17:00:43 2021 +0200
Commit: Thorsten Behrens <thorsten.behrens at allotropia.de>
CommitDate: Thu Apr 15 02:44:54 2021 +0200
xmlsec: fix signing documents on WNT
Duplicate ds:X509Certificate elements cause:
warn:xmlsecurity.comp:9604:3820:xmlsecurity/source/helper/xmlsignaturehelper.cxx:658: X509Data do not form a chain: certificate in cycle:
(regression from 5af5ea893bcb8a8eb472ac11133da10e5a604e66)
Change-Id: I3d319a2f74dbec17b73f1c7bb8f4efe4e335f0ac
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113746
Tested-by: Mike Kaganski <mike.kaganski at collabora.com>
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl at allotropia.de>
(cherry picked from commit ae08aa8a095832ae2a88eac14f9680ac8d3a13b6)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113752
Reviewed-by: Thorsten Behrens <thorsten.behrens at allotropia.de>
(cherry picked from commit 0ab3a264ba8d732cffa42a069c9aa50dab44e99f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113753
Tested-by: Samuel Mehrbrodt <samuel.mehrbrodt at allotropia.de>
Reviewed-by: Samuel Mehrbrodt <samuel.mehrbrodt at allotropia.de>
(cherry picked from commit 69e2488acea640974fe7946f4cef18fed0ec4c30)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113755
Tested-by: Michael Stahl <michael.stahl at allotropia.de>
diff --git a/external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1 b/external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
new file mode 100644
index 000000000000..51607ca6ee73
--- /dev/null
+++ b/external/xmlsec/0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
@@ -0,0 +1,68 @@
+From a39b110cb2c25680259a38b2f397b350151bc6e7 Mon Sep 17 00:00:00 2001
+From: Michael Stahl <michael.stahl at allotropia.de>
+Date: Wed, 7 Apr 2021 16:43:48 +0200
+Subject: [PATCH] xmlSecX509DataGetNodeContent(): don't return 0 for non-empty
+ elements
+
+LibreOffice wants to write the content of KeyInfo itself and thus writes
+X509Certificate element with content.
+
+But then xmlSecMSCngKeyDataX509XmlWrite() writes a duplicate
+X509Certificate element, which then makes a new additional consistency
+check in LO unhappy.
+
+The duplicate is written because xmlSecX509DataGetNodeContent() returns
+0 because it only checks for empty nodes; if there are only non-empty
+nodes a fallback to XMLSEC_X509DATA_DEFAULT occurs in all backends.
+
+Change the return value to be non-0 without changing the signature of
+the function, as it is apparently public.
+
+This doesn't happen in LO in the NSS backend due to another accident,
+where the private key flag isn't set when the X509Certificate is read,
+but otherwise the code is the same.
+---
+ src/x509.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/x509.c b/src/x509.c
+index ed8788ae..dac8bd2b 100644
+--- a/src/x509.c
++++ b/src/x509.c
+@@ -60,22 +60,33 @@ xmlSecX509DataGetNodeContent (xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_X509DATA_CERTIFICATE_NODE;
++ } else {
++ /* ensure return value isn't 0 if there are non-empty elements */
++ content |= (XMLSEC_X509DATA_CERTIFICATE_NODE << 16);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_X509DATA_SUBJECTNAME_NODE;
++ } else {
++ content |= (XMLSEC_X509DATA_SUBJECTNAME_NODE << 16);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_X509DATA_ISSUERSERIAL_NODE;
++ } else {
++ content |= (XMLSEC_X509DATA_ISSUERSERIAL_NODE << 16);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_X509DATA_SKI_NODE;
++ } else {
++ content |= (XMLSEC_X509DATA_SKI_NODE << 16);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) {
+ if(xmlSecIsEmptyNode(cur) == 1) {
+ content |= XMLSEC_X509DATA_CRL_NODE;
++ } else {
++ content |= (XMLSEC_X509DATA_CRL_NODE << 16);
+ }
+ } else {
+ /* todo: fail on unknown child node? */
+--
+2.30.2
+
diff --git a/external/xmlsec/UnpackedTarball_xmlsec.mk b/external/xmlsec/UnpackedTarball_xmlsec.mk
index e4d092bef019..76293fe31e42 100644
--- a/external/xmlsec/UnpackedTarball_xmlsec.mk
+++ b/external/xmlsec/UnpackedTarball_xmlsec.mk
@@ -8,6 +8,7 @@
#
xmlsec_patches :=
+xmlsec_patches += 0001-xmlSecX509DataGetNodeContent-don-t-return-0-for-non-.patch.1
$(eval $(call gb_UnpackedTarball_UnpackedTarball,xmlsec))
commit b1b26d6e83da7d38a9c6f69052484c4d62715848
Author: Michael Stahl <michael.stahl at allotropia.de>
AuthorDate: Tue Mar 30 17:37:31 2021 +0200
Commit: Thorsten Behrens <thorsten.behrens at allotropia.de>
CommitDate: Thu Apr 15 02:44:53 2021 +0200
xmlsecurity: replace OOXMLSecParser implementation
This is similar to 12b15be8f4f930a04d8056b9219ac969b42a9784 and following
commits, but OOXMLSecParser has some differences to XSecParser, such as
using a ds:Manifest, and requires a couple extra namespaces.
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113381
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
(cherry picked from commit cc1d19f7bbaefa5fb22ebd1344112755068b93c9)
Change-Id: I56e39d9609db8fcad50ca1632ff482c1f0a30ff5
diff --git a/include/xmloff/xmlnmspe.hxx b/include/xmloff/xmlnmspe.hxx
index cc97a9c5aaa4..a7505a64190d 100644
--- a/include/xmloff/xmlnmspe.hxx
+++ b/include/xmloff/xmlnmspe.hxx
@@ -145,6 +145,9 @@ const sal_uInt16 XML_NAMESPACE_DSIG = 201;
const sal_uInt16 XML_NAMESPACE_DS = 202;
const sal_uInt16 XML_NAMESPACE_XADES132 = 203;
const sal_uInt16 XML_NAMESPACE_XADES141 = 204;
+// OOXML digital signature extension namespaces, also based on xmldsig-core
+const sal_uInt16 XML_NAMESPACE_MDSSI = 205;
+const sal_uInt16 XML_NAMESPACE_MSODIGSIG = 206;
#endif // INCLUDED_XMLOFF_XMLNMSPE_HXX
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx
index a25872fc057d..42f226f57d14 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -11,32 +11,1241 @@
#include "ooxmlsecparser.hxx"
#include <xmlsignaturehelper.hxx>
#include <xsecctl.hxx>
+
+#include <xmloff/xmlnmspe.hxx>
+#include <xmloff/xmlimp.hxx>
+
+#include <com/sun/star/xml/sax/SAXException.hpp>
+
#include <sal/log.hxx>
-using namespace com::sun::star;
+using namespace com::sun::star;
+
+class OOXMLSecParser::Context
+{
+ protected:
+ friend class OOXMLSecParser;
+ OOXMLSecParser & m_rParser;
+ private:
+ std::unique_ptr<SvXMLNamespaceMap> m_pOldNamespaceMap;
+
+ public:
+ Context(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : m_rParser(rParser)
+ , m_pOldNamespaceMap(std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual ~Context() = default;
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& /*xAttrs*/)
+ {
+ }
+
+ virtual void EndElement()
+ {
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/);
+
+ virtual void Characters(OUString const& /*rChars*/)
+ {
+ }
+};
+
+// it's possible that an unsupported element has an Id attribute and a
+// ds:Reference digesting it - probably this means XSecController needs to know
+// about it. (For known elements, the Id attribute is only processed according
+// to the schema.)
+class OOXMLSecParser::UnknownContext
+ : public OOXMLSecParser::Context
+{
+ public:
+ UnknownContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ m_rParser.HandleIdAttr(xAttrs);
+ }
+};
+
+auto OOXMLSecParser::Context::CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const /*nNamespace*/, OUString const& /*rName*/)
+-> std::unique_ptr<Context>
+{
+ // default: create new base context
+ return std::make_unique<UnknownContext>(m_rParser, std::move(pOldNamespaceMap));
+}
+
+/**
+note: anything in ds:Object should be trusted *only* if there is a ds:Reference
+ to it so it is signed (exception: the xades:EncapsulatedX509Certificate).
+ ds:SignedInfo precedes all ds:Object.
+
+ There may be multiple ds:Signature for purpose of counter-signatures
+ but the way XAdES describes these, only the ds:SignatureValue element
+ would be referenced, so requiring a ds:Reference for anything in
+ ds:Object shouldn't cause issues.
+ */
+class OOXMLSecParser::ReferencedContextImpl
+ : public OOXMLSecParser::Context
+{
+ protected:
+ bool m_isReferenced;
+
+ public:
+ ReferencedContextImpl(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_isReferenced(isReferenced)
+ {
+ }
+
+ OUString CheckIdAttrReferenced(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs)
+ {
+ OUString const id(m_rParser.HandleIdAttr(xAttrs));
+ if (!id.isEmpty() && m_rParser.m_pXSecController->haveReferenceForId(id))
+ {
+ m_isReferenced = true;
+ }
+ return id;
+ }
+};
+
+class OOXMLSecParser::DsX509CertificateContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ DsX509CertificateContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::DsX509SerialNumberContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ DsX509SerialNumberContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::DsX509IssuerNameContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ DsX509IssuerNameContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::DsX509IssuerSerialContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rX509IssuerName;
+ OUString & m_rX509SerialNumber;
+
+ public:
+ DsX509IssuerSerialContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rIssuerName, OUString & rSerialNumber)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rX509IssuerName(rIssuerName)
+ , m_rX509SerialNumber(rSerialNumber)
+ {
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerName")
+ {
+ return std::make_unique<DsX509IssuerNameContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509IssuerName);
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "X509SerialNumber")
+ {
+ return std::make_unique<DsX509SerialNumberContext>(m_rParser, std::move(pOldNamespaceMap), m_rX509SerialNumber);
+ }
+ // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+/// can't be sure what is supposed to happen here because the spec is clear as mud
+class OOXMLSecParser::DsX509DataContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ // sigh... "No ordering is implied by the above constraints."
+ // so store the ball of mud in vectors and try to figure it out later.
+ std::vector<std::pair<OUString, OUString>> m_X509IssuerSerials;
+ std::vector<OUString> m_X509Certificates;
+
+ public:
+ DsX509DataContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void EndElement() override
+ {
+ m_rParser.m_pXSecController->setX509Data(m_X509IssuerSerials, m_X509Certificates);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "X509IssuerSerial")
+ {
+ m_X509IssuerSerials.emplace_back();
+ return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerSerials.back().first, m_X509IssuerSerials.back().second);
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "X509Certificate")
+ {
+ m_X509Certificates.emplace_back();
+ return std::make_unique<DsX509CertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_X509Certificates.back());
+ }
+ // missing: ds:X509SKI, ds:X509SubjectName, ds:X509CRL
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsKeyInfoContext
+ : public OOXMLSecParser::Context
+{
+ public:
+ DsKeyInfoContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ m_rParser.HandleIdAttr(xAttrs);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "X509Data")
+ {
+ return std::make_unique<DsX509DataContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ // missing: ds:PGPData
+ // missing: ds:KeyName, ds:KeyValue, ds:RetrievalMethod, ds:SPKIData, ds:MgmtData
+ // (old code would read ds:Transform inside ds:RetrievalMethod but
+ // presumably that was a bug)
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+
+};
+
+class OOXMLSecParser::DsSignatureValueContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString m_Value;
+
+ public:
+ DsSignatureValueContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ m_rParser.HandleIdAttr(xAttrs);
+ }
+
+ virtual void EndElement() override
+ {
+ m_rParser.m_pXSecController->setSignatureValue(m_Value);
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_Value += rChars;
+ }
+};
+
+class OOXMLSecParser::DsDigestValueContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ DsDigestValueContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& /*xAttrs*/) override
+ {
+ m_rValue.clear();
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::DsDigestMethodContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ sal_Int32 & m_rReferenceDigestID;
+
+ public:
+ DsDigestMethodContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_Int32 & rReferenceDigestID)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rReferenceDigestID(rReferenceDigestID)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ OUString ouAlgorithm = xAttrs->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
+ && ouAlgorithm != ALGO_XMLDSIGSHA512,
+ "xmlsecurity.helper", "Algorithm neither SHA1, SHA256 nor SHA512");
+ if (ouAlgorithm == ALGO_XMLDSIGSHA1)
+ m_rReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+ else if (ouAlgorithm == ALGO_XMLDSIGSHA256)
+ m_rReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+ else if (ouAlgorithm == ALGO_XMLDSIGSHA512)
+ m_rReferenceDigestID = css::xml::crypto::DigestID::SHA512;
+ else
+ m_rReferenceDigestID = 0;
+ }
+ }
+};
+
+class OOXMLSecParser::DsTransformContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ bool & m_rIsC14N;
+
+ public:
+ DsTransformContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool & rIsC14N)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rIsC14N(rIsC14N)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ OUString aAlgorithm = xAttrs->getValueByName("Algorithm");
+
+ if (aAlgorithm == ALGO_RELATIONSHIP)
+ {
+ m_rIsC14N = true;
+ }
+ }
+};
+
+class OOXMLSecParser::DsTransformsContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ bool & m_rIsC14N;
+
+ public:
+ DsTransformsContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool & rIsC14N)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rIsC14N(rIsC14N)
+ {
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "Transform")
+ {
+ return std::make_unique<DsTransformContext>(m_rParser, std::move(pOldNamespaceMap), m_rIsC14N);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsReferenceContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString m_URI;
+ OUString m_Type;
+ OUString m_DigestValue;
+ bool m_IsC14N = false;
+ // Relevant for ODF. The digest algorithm selected by the DigestMethod
+ // element's Algorithm attribute. @see css::xml::crypto::DigestID.
+ sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA256;
+
+ public:
+ DsReferenceContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ m_rParser.HandleIdAttr(xAttrs);
+
+ m_URI = xAttrs->getValueByName("URI");
+ SAL_WARN_IF(m_URI.isEmpty(), "xmlsecurity.helper", "URI is empty");
+ // Remember the type of this reference.
+ m_Type = xAttrs->getValueByName("Type");
+ }
+
+ virtual void EndElement() override
+ {
+ if (m_URI.startsWith("#"))
+ {
+ /*
+ * remove the first character '#' from the attribute value
+ */
+ m_rParser.m_pXSecController->addReference(m_URI.copy(1), m_nReferenceDigestID, m_Type);
+ }
+ else
+ {
+ if (m_IsC14N) // this is determined by nested ds:Transform
+ {
+ m_rParser.m_pXSecController->addStreamReference(m_URI, false, m_nReferenceDigestID);
+ }
+ else
+ /*
+ * it must be an octet stream
+ */
+ {
+ m_rParser.m_pXSecController->addStreamReference(m_URI, true, m_nReferenceDigestID);
+ }
+ }
+
+ m_rParser.m_pXSecController->setDigestValue(m_nReferenceDigestID, m_DigestValue);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "Transforms")
+ {
+ return std::make_unique<DsTransformsContext>(m_rParser, std::move(pOldNamespaceMap), m_IsC14N);
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
+ {
+ return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_nReferenceDigestID);
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
+ {
+ return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_DigestValue);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsSignatureMethodContext
+ : public OOXMLSecParser::Context
+{
+ public:
+ DsSignatureMethodContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ OUString ouAlgorithm = xAttrs->getValueByName("Algorithm");
+ if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
+ || ouAlgorithm == ALGO_ECDSASHA512)
+ {
+ m_rParser.m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
+ }
+ }
+};
+
+class OOXMLSecParser::DsSignedInfoContext
+ : public OOXMLSecParser::Context
+{
+ public:
+ DsSignedInfoContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ m_rParser.HandleIdAttr(xAttrs);
+ }
+
+ virtual void EndElement() override
+ {
+ m_rParser.m_pXSecController->setReferenceCount();
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureMethod")
+ {
+ return std::make_unique<DsSignatureMethodContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "Reference")
+ {
+ return std::make_unique<DsReferenceContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ // missing: ds:CanonicalizationMethod
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::XadesCertDigestContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rDigestValue;
+ sal_Int32 & m_rReferenceDigestID;
+
+ public:
+ XadesCertDigestContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rDigestValue, sal_Int32 & rReferenceDigestID)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rDigestValue(rDigestValue)
+ , m_rReferenceDigestID(rReferenceDigestID)
+ {
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "DigestMethod")
+ {
+ return std::make_unique<DsDigestMethodContext>(m_rParser, std::move(pOldNamespaceMap), m_rReferenceDigestID);
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "DigestValue")
+ {
+ return std::make_unique<DsDigestValueContext>(m_rParser, std::move(pOldNamespaceMap), m_rDigestValue);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::XadesCertContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ private:
+ sal_Int32 m_nReferenceDigestID = css::xml::crypto::DigestID::SHA1;
+ OUString m_CertDigest;
+ OUString m_X509IssuerName;
+ OUString m_X509SerialNumber;
+
+ public:
+ XadesCertContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void EndElement() override
+ {
+ if (m_isReferenced)
+ {
+ m_rParser.m_pXSecController->setX509CertDigest(m_CertDigest, m_nReferenceDigestID, m_X509IssuerName, m_X509SerialNumber);
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned xades:Cert");
+ }
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "CertDigest")
+ {
+ return std::make_unique<XadesCertDigestContext>(m_rParser, std::move(pOldNamespaceMap), m_CertDigest, m_nReferenceDigestID);
+ }
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "IssuerSerial")
+ {
+ return std::make_unique<DsX509IssuerSerialContext>(m_rParser, std::move(pOldNamespaceMap), m_X509IssuerName, m_X509SerialNumber);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::XadesSigningCertificateContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ public:
+ XadesSigningCertificateContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "Cert")
+ {
+ return std::make_unique<XadesCertContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::XadesSigningTimeContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ private:
+ OUString m_Value;
+
+ public:
+ XadesSigningTimeContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void EndElement() override
+ {
+ if (m_isReferenced)
+ {
+ m_rParser.m_pXSecController->setDate("", m_Value);
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SigningTime");
+ }
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_Value += rChars;
+ }
+};
+
+class OOXMLSecParser::XadesSignedSignaturePropertiesContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ public:
+ XadesSignedSignaturePropertiesContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ CheckIdAttrReferenced(xAttrs);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningTime")
+ {
+ return std::make_unique<XadesSigningTimeContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SigningCertificate")
+ {
+ return std::make_unique<XadesSigningCertificateContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ // missing: xades:SignaturePolicyIdentifier, xades:SignatureProductionPlace, xades:SignerRole
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::XadesSignedPropertiesContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ public:
+ XadesSignedPropertiesContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ CheckIdAttrReferenced(xAttrs);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedSignatureProperties")
+ {
+ return std::make_unique<XadesSignedSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ // missing: xades:SignedDataObjectProperties
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::XadesQualifyingPropertiesContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ public:
+ XadesQualifyingPropertiesContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ CheckIdAttrReferenced(xAttrs);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "SignedProperties")
+ {
+ return std::make_unique<XadesSignedPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ // missing: xades:UnsignedSignatureProperties
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::MsodigsigSetupIDContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ MsodigsigSetupIDContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::MsodigsigSignatureCommentsContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ MsodigsigSignatureCommentsContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::MsodigsigSignatureInfoV1Context
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ private:
+ OUString m_SetupID;
+ OUString m_SignatureComments;
+
+ public:
+ MsodigsigSignatureInfoV1Context(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ CheckIdAttrReferenced(xAttrs);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SetupID")
+ {
+ return std::make_unique<MsodigsigSetupIDContext>(m_rParser, std::move(pOldNamespaceMap), m_SetupID);
+ }
+ if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SignatureComments")
+ {
+ return std::make_unique<MsodigsigSignatureCommentsContext>(m_rParser, std::move(pOldNamespaceMap), m_SignatureComments);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+
+ virtual void EndElement() override
+ {
+ if (m_isReferenced)
+ {
+ if (!m_SetupID.isEmpty())
+ {
+ m_rParser.m_pXSecController->setSignatureLineId(m_SetupID);
+ }
+ if (!m_SignatureComments.isEmpty())
+ {
+ m_rParser.m_pXSecController->setDescription("", m_SignatureComments);
+
+ }
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureInfoV1");
+ }
+ }
+};
+
+class OOXMLSecParser::MdssiValueContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ MdssiValueContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_rValue += rChars;
+ }
+};
+
+class OOXMLSecParser::MdssiSignatureTimeContext
+ : public OOXMLSecParser::Context
+{
+ private:
+ OUString & m_rValue;
+
+ public:
+ MdssiSignatureTimeContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ OUString & rValue)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ , m_rValue(rValue)
+ {
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_MDSSI && rName == "Value")
+ {
+ return std::make_unique<MdssiValueContext>(m_rParser, std::move(pOldNamespaceMap), m_rValue);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+
+class OOXMLSecParser::DsSignaturePropertyContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ private:
+ enum class SignatureProperty { Unknown, Date, Info };
+ SignatureProperty m_Property = SignatureProperty::Unknown;
+ OUString m_Id;
+ OUString m_Value;
+
+ public:
+ DsSignaturePropertyContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ m_Id = CheckIdAttrReferenced(xAttrs);
+ }
+
+ virtual void EndElement() override
+ {
+ if (m_isReferenced)
+ {
+ switch (m_Property)
+ {
+ case SignatureProperty::Unknown:
+ SAL_INFO("xmlsecurity.helper", "Unknown property in ds:Object ignored");
+ break;
+ case SignatureProperty::Info:
+ break; // handled by child context
+ case SignatureProperty::Date:
+ m_rParser.m_pXSecController->setDate(m_Id, m_Value);
+ break;
+ }
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureProperty");
+ }
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_MDSSI && rName == "SignatureTime")
+ {
+ m_Property = SignatureProperty::Date;
+ return std::make_unique<MdssiSignatureTimeContext>(m_rParser, std::move(pOldNamespaceMap), m_Value);
+ }
+ if (nNamespace == XML_NAMESPACE_MSODIGSIG && rName == "SignatureInfoV1")
+ {
+ return std::make_unique<MsodigsigSignatureInfoV1Context>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsSignaturePropertiesContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ public:
+ DsSignaturePropertiesContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ CheckIdAttrReferenced(xAttrs);
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperty")
+ {
+ return std::make_unique<DsSignaturePropertyContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsManifestContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ public:
+ DsManifestContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ bool const isReferenced)
+ : ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), isReferenced)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ CheckIdAttrReferenced(xAttrs);
+ }
+
+#if 0
+ ???
+ virtual void EndElement() override
+ {
+ m_rParser.m_pXSecController->setReferenceCount();
+ }
+#endif
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "Reference")
+ {
+ return std::make_unique<DsReferenceContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ // missing: ds:CanonicalizationMethod
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsObjectContext
+ : public OOXMLSecParser::ReferencedContextImpl
+{
+ enum class Mode { Default, ValidSignatureLineImage, InvalidSignatureLineImage };
+ Mode m_Mode = Mode::Default;
+ OUString m_Value;
+
+ public:
+ DsObjectContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ // init with "false" here - the Signature element can't be referenced by its child
+ : OOXMLSecParser::ReferencedContextImpl(rParser, std::move(pOldNamespaceMap), false)
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ OUString const id(CheckIdAttrReferenced(xAttrs));
+ if (id == "idValidSigLnImg")
+ {
+ m_Mode = Mode::ValidSignatureLineImage;
+ }
+ else if (id == "idInvalidSigLnImg")
+ {
+ m_Mode = Mode::InvalidSignatureLineImage;
+ }
+ }
+
+ virtual void EndElement() override
+ {
+ switch (m_Mode)
+ {
+ case Mode::ValidSignatureLineImage:
+ if (m_isReferenced)
+ {
+ m_rParser.m_pXSecController->setValidSignatureImage(m_Value);
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineValidImage");
+ }
+ break;
+ case Mode::InvalidSignatureLineImage:
+ if (m_isReferenced)
+ {
+ m_rParser.m_pXSecController->setInvalidSignatureImage(m_Value);
+ }
+ else
+ {
+ SAL_INFO("xmlsecurity.helper", "ignoring unsigned SignatureLineInvalidImage");
+ }
+ break;
+ case Mode::Default:
+ break;
+ }
+ }
+
+ virtual void Characters(OUString const& rChars) override
+ {
+ m_Value += rChars;
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureProperties")
+ {
+ return std::make_unique<DsSignaturePropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ if (nNamespace == XML_NAMESPACE_XADES132 && rName == "QualifyingProperties")
+ {
+ return std::make_unique<XadesQualifyingPropertiesContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "Manifest")
+ {
+ return std::make_unique<DsManifestContext>(m_rParser, std::move(pOldNamespaceMap), m_isReferenced);
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
+class OOXMLSecParser::DsSignatureContext
+ : public OOXMLSecParser::Context
+{
+ public:
+ DsSignatureContext(OOXMLSecParser & rParser,
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap)
+ : OOXMLSecParser::Context(rParser, std::move(pOldNamespaceMap))
+ {
+ }
+
+ virtual void StartElement(
+ css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs) override
+ {
+ OUString const ouIdAttr(m_rParser.HandleIdAttr(xAttrs));
+ m_rParser.m_rXMLSignatureHelper.StartVerifySignatureElement();
+ m_rParser.m_pXSecController->addSignature();
+ if (!ouIdAttr.isEmpty())
+ {
+ m_rParser.m_pXSecController->setId( ouIdAttr );
+ }
+ }
+
+ virtual std::unique_ptr<Context> CreateChildContext(
+ std::unique_ptr<SvXMLNamespaceMap> pOldNamespaceMap,
+ sal_uInt16 const nNamespace, OUString const& rName) override
+ {
+ if (nNamespace == XML_NAMESPACE_DS && rName == "SignedInfo")
+ {
+ return std::make_unique<DsSignedInfoContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "SignatureValue")
+ {
+ return std::make_unique<DsSignatureValueContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "KeyInfo")
+ {
+ return std::make_unique<DsKeyInfoContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ if (nNamespace == XML_NAMESPACE_DS && rName == "Object")
+ {
+ return std::make_unique<DsObjectContext>(m_rParser, std::move(pOldNamespaceMap));
+ }
+ return OOXMLSecParser::Context::CreateChildContext(std::move(pOldNamespaceMap), nNamespace, rName);
+ }
+};
+
OOXMLSecParser::OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController)
- : m_pXSecController(pXSecController)
- ,m_bInDigestValue(false)
- ,m_bInSignatureValue(false)
- ,m_bInX509Certificate(false)
- ,m_bInMdssiValue(false)
- ,m_bInSignatureComments(false)
- ,m_bInX509IssuerName(false)
- ,m_bInX509SerialNumber(false)
- ,m_bInCertDigest(false)
- ,m_bInValidSignatureImage(false)
- ,m_bInInvalidSignatureImage(false)
- ,m_bInSignatureLineId(false)
- ,m_bReferenceUnresolved(false)
+ : m_pNamespaceMap(new SvXMLNamespaceMap)
+ , m_pXSecController(pXSecController)
,m_rXMLSignatureHelper(rXMLSignatureHelper)
{
+ using namespace xmloff::token;
+ m_pNamespaceMap->Add( GetXMLToken(XML_XML), GetXMLToken(XML_N_XML), XML_NAMESPACE_XML );
+ m_pNamespaceMap->Add( "_ds", GetXMLToken(XML_N_DS), XML_NAMESPACE_DS );
+ m_pNamespaceMap->Add( "_xades132", GetXMLToken(XML_N_XADES132), XML_NAMESPACE_XADES132);
+ m_pNamespaceMap->Add( "_xades141", GetXMLToken(XML_N_XADES141), XML_NAMESPACE_XADES141);
+ m_pNamespaceMap->Add( "_dc", GetXMLToken(XML_N_DC), XML_NAMESPACE_DC );
+ m_pNamespaceMap->Add( "_mdssi", NS_MDSSI, XML_NAMESPACE_MDSSI );
+ m_pNamespaceMap->Add( "_msodigsig", "http://schemas.microsoft.com/office/2006/digsig", XML_NAMESPACE_MSODIGSIG );
+ m_pNamespaceMap->Add( "_office_libo",
+ GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT);
}
OOXMLSecParser::~OOXMLSecParser()
{
}
+OUString OOXMLSecParser::HandleIdAttr(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs)
+{
+ OUString const aId = xAttrs->getValueByName("Id");
+ if (!aId.isEmpty())
+ {
+ m_pXSecController->collectToVerify(aId);
+ }
+ return aId;
+}
+
void SAL_CALL OOXMLSecParser::startDocument()
{
if (m_xNextHandler.is())
@@ -51,231 +1260,69 @@ void SAL_CALL OOXMLSecParser::endDocument()
void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const uno::Reference<xml::sax::XAttributeList>& xAttribs)
{
- OUString aId = xAttribs->getValueByName("Id");
- if (!aId.isEmpty())
- m_pXSecController->collectToVerify(aId);
+ assert(m_pNamespaceMap);
+ std::unique_ptr<SvXMLNamespaceMap> pRewindMap(
+ SvXMLImport::processNSAttributes(m_pNamespaceMap, nullptr, xAttribs));
- if (rName == "Signature")
- {
- m_rXMLSignatureHelper.StartVerifySignatureElement();
- m_pXSecController->addSignature();
- if (!aId.isEmpty())
- m_pXSecController->setId(aId);
- }
- else if (rName == "SignatureMethod")
- {
- OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
- if (ouAlgorithm == ALGO_ECDSASHA1 || ouAlgorithm == ALGO_ECDSASHA256
- || ouAlgorithm == ALGO_ECDSASHA512)
- m_pXSecController->setSignatureMethod(svl::crypto::SignatureMethodAlgorithm::ECDSA);
- }
- else if (rName == "Reference")
- {
- OUString aURI = xAttribs->getValueByName("URI");
- if (aURI.startsWith("#"))
- m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1, OUString());
- else
- {
- m_aReferenceURI = aURI;
- m_bReferenceUnresolved = true;
- }
- }
- else if (rName == "Transform")
- {
- if (m_bReferenceUnresolved)
- {
- OUString aAlgorithm = xAttribs->getValueByName("Algorithm");
- if (aAlgorithm == ALGO_RELATIONSHIP)
- {
- m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false, /*nDigestID=*/xml::crypto::DigestID::SHA256);
- m_bReferenceUnresolved = false;
- }
- }
- }
- else if (rName == "DigestValue" && !m_bInCertDigest)
- {
- m_aDigestValue.clear();
- m_bInDigestValue = true;
- }
- else if (rName == "SignatureValue")
- {
- m_aSignatureValue.clear();
- m_bInSignatureValue = true;
- }
- else if (rName == "X509Certificate")
- {
- m_aX509Certificate.clear();
- m_bInX509Certificate = true;
- }
- else if (rName == "mdssi:Value")
- {
- m_aMdssiValue.clear();
- m_bInMdssiValue = true;
- }
- else if (rName == "SignatureComments")
- {
- m_aSignatureComments.clear();
- m_bInSignatureComments = true;
- }
- else if (rName == "X509IssuerName")
- {
- m_aX509IssuerName.clear();
- m_bInX509IssuerName = true;
- }
- else if (rName == "X509SerialNumber")
- {
- m_aX509SerialNumber.clear();
- m_bInX509SerialNumber = true;
- }
- else if (rName == "xd:CertDigest")
- {
- m_aCertDigest.clear();
- m_bInCertDigest = true;
- }
- else if (rName == "Object")
+ OUString localName;
+ sal_uInt16 const nPrefix(m_pNamespaceMap->GetKeyByAttrName(rName, &localName));
+
+ std::unique_ptr<Context> pContext;
+
+ if (m_ContextStack.empty())
{
- OUString sId = xAttribs->getValueByName("Id");
- if (sId == "idValidSigLnImg")
- {
- m_aValidSignatureImage.clear();
- m_bInValidSignatureImage = true;
- }
- else if (sId == "idInvalidSigLnImg")
+ if (nPrefix == XML_NAMESPACE_DS
+ && localName == "Signature")
{
- m_aInvalidSignatureImage.clear();
- m_bInInvalidSignatureImage = true;
+ pContext.reset(new DsSignatureContext(*this, std::move(pRewindMap)));
}
else
{
- SAL_INFO("xmlsecurity.ooxml", "Unknown 'Object' child element: " << rName);
+ throw css::xml::sax::SAXException(
+ "xmlsecurity: unexpected root element", nullptr,
+ css::uno::Any());
}
}
- else if (rName == "SetupID")
- {
- m_aSignatureLineId.clear();
- m_bInSignatureLineId = true;
- }
else
{
- SAL_INFO("xmlsecurity.ooxml", "Unknown xml element: " << rName);
+ pContext = m_ContextStack.top()->CreateChildContext(
+ std::move(pRewindMap), nPrefix, localName);
}
+ m_ContextStack.push(std::move(pContext));
+ assert(!pRewindMap);
+
+ m_ContextStack.top()->StartElement(xAttribs);
+
if (m_xNextHandler.is())
+ {
m_xNextHandler->startElement(rName, xAttribs);
+ }
+
}
void SAL_CALL OOXMLSecParser::endElement(const OUString& rName)
{
- if (rName == "SignedInfo")
- m_pXSecController->setReferenceCount();
- else if (rName == "Reference")
- {
- if (m_bReferenceUnresolved)
- {
- // No transform algorithm found, assume binary.
- m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true, /*nDigestID=*/xml::crypto::DigestID::SHA256);
- m_bReferenceUnresolved = false;
- }
- m_pXSecController->setDigestValue(xml::crypto::DigestID::SHA256, m_aDigestValue);
- }
- else if (rName == "DigestValue" && !m_bInCertDigest)
- m_bInDigestValue = false;
- else if (rName == "SignatureValue")
- {
- m_pXSecController->setSignatureValue(m_aSignatureValue);
- m_bInSignatureValue = false;
- }
- else if (rName == "X509Data")
- {
- std::vector<std::pair<OUString, OUString>> X509IssuerSerials;
- std::vector<OUString> X509Certificates;
- if (!m_aX509Certificate.isEmpty())
- {
- X509Certificates.emplace_back(m_aX509Certificate);
- }
- if (!m_aX509IssuerName.isEmpty() && !m_aX509SerialNumber.isEmpty())
- {
- X509IssuerSerials.emplace_back(m_aX509IssuerName, m_aX509SerialNumber);
- }
- m_pXSecController->setX509Data(X509IssuerSerials, X509Certificates);
- }
- else if (rName == "X509Certificate")
- {
- m_bInX509Certificate = false;
- }
- else if (rName == "mdssi:Value")
- {
- m_pXSecController->setDate("", m_aMdssiValue);
- m_bInMdssiValue = false;
- }
- else if (rName == "SignatureComments")
- {
- m_pXSecController->setDescription("", m_aSignatureComments);
- m_bInSignatureComments = false;
- }
- else if (rName == "X509IssuerName")
- {
- m_bInX509IssuerName = false;
- }
- else if (rName == "X509SerialNumber")
- {
- m_bInX509SerialNumber = false;
- }
- else if (rName == "xd:Cert")
- {
- m_pXSecController->setX509CertDigest(m_aCertDigest, css::xml::crypto::DigestID::SHA1, m_aX509IssuerName, m_aX509SerialNumber);
- }
- else if (rName == "xd:CertDigest")
- {
- m_bInCertDigest = false;
- }
- else if (rName == "Object")
+ assert(!m_ContextStack.empty()); // this should be checked by sax parser?
+
+ m_ContextStack.top()->EndElement();
+
+ if (m_xNextHandler.is())
{
- if (m_bInValidSignatureImage)
- {
- m_pXSecController->setValidSignatureImage(m_aValidSignatureImage);
- m_bInValidSignatureImage = false;
- }
- else if (m_bInInvalidSignatureImage)
- {
- m_pXSecController->setInvalidSignatureImage(m_aInvalidSignatureImage);
- m_bInInvalidSignatureImage = false;
- }
+ m_xNextHandler->endElement(rName);
}
- else if (rName == "SetupID")
+
+ if (m_ContextStack.top()->m_pOldNamespaceMap)
{
- m_pXSecController->setSignatureLineId(m_aSignatureLineId);
- m_bInSignatureLineId = false;
+ m_pNamespaceMap = std::move(m_ContextStack.top()->m_pOldNamespaceMap);
}
-
- if (m_xNextHandler.is())
- m_xNextHandler->endElement(rName);
+ m_ContextStack.pop();
}
void SAL_CALL OOXMLSecParser::characters(const OUString& rChars)
{
- if (m_bInDigestValue && !m_bInCertDigest)
- m_aDigestValue += rChars;
- else if (m_bInSignatureValue)
- m_aSignatureValue += rChars;
- else if (m_bInX509Certificate)
- m_aX509Certificate += rChars;
- else if (m_bInMdssiValue)
- m_aMdssiValue += rChars;
- else if (m_bInSignatureComments)
- m_aSignatureComments += rChars;
- else if (m_bInX509IssuerName)
- m_aX509IssuerName += rChars;
- else if (m_bInX509SerialNumber)
- m_aX509SerialNumber += rChars;
- else if (m_bInCertDigest)
- m_aCertDigest += rChars;
- else if (m_bInValidSignatureImage)
- m_aValidSignatureImage += rChars;
- else if (m_bInInvalidSignatureImage)
- m_aInvalidSignatureImage += rChars;
- else if (m_bInSignatureLineId)
- m_aSignatureLineId += rChars;
+ assert(!m_ContextStack.empty()); // this should be checked by sax parser?
+ m_ContextStack.top()->Characters(rChars);
if (m_xNextHandler.is())
m_xNextHandler->characters(rChars);
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.hxx b/xmlsecurity/source/helper/ooxmlsecparser.hxx
index d3c199147255..540028b22fc9 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.hxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.hxx
@@ -15,6 +15,10 @@
#include <cppuhelper/implbase.hxx>
+#include <xmloff/nmspmap.hxx>
+
+#include <stack>
+
class XSecController;
class XMLSignatureHelper;
@@ -25,38 +29,62 @@ class OOXMLSecParser: public cppu::WeakImplHelper
css::lang::XInitialization
>
{
+public:
+ class Context;
+private:
+ class UnknownContext;
+ class ReferencedContextImpl;
+ class DsX509CertificateContext;
+ class DsX509SerialNumberContext;
+ class DsX509IssuerNameContext;
+ class DsX509IssuerSerialContext;
+ class DsX509DataContext;
+ class DsKeyInfoContext;
+ class DsSignatureValueContext;
+ class DsDigestValueContext;
+ class DsDigestMethodContext;
+ class DsTransformContext;
+ class DsTransformsContext;
+ class DsReferenceContext;
+ class DsSignatureMethodContext;
+ class DsSignedInfoContext;
+ class XadesEncapsulatedX509CertificateContext;
+ class XadesCertificateValuesContext;
+ class XadesUnsignedSignaturePropertiesContext;
+ class XadesUnsignedPropertiesContext;
+ class XadesCertDigestContext;
+ class XadesCertContext;
+ class XadesSigningCertificateContext;
+ class XadesSigningTimeContext;
+ class XadesSignedSignaturePropertiesContext;
+ class XadesSignedPropertiesContext;
+ class XadesQualifyingPropertiesContext;
+ class MdssiValueContext;
+ class MdssiSignatureTimeContext;
+ class MsodigsigSetupIDContext;
+ class MsodigsigSignatureCommentsContext;
+ class MsodigsigSignatureInfoV1Context;
+ class DsSignaturePropertyContext;
+ class DsSignaturePropertiesContext;
+ class DsManifestContext;
+ class DsObjectContext;
+ class DsSignatureContext;
+ class DsigSignaturesContext;
+
+ std::stack<std::unique_ptr<Context>> m_ContextStack;
+ std::unique_ptr<SvXMLNamespaceMap> m_pNamespaceMap;
+
XSecController* m_pXSecController;
css::uno::Reference<css::xml::sax::XDocumentHandler> m_xNextHandler;
- bool m_bInDigestValue;
- OUString m_aDigestValue;
- bool m_bInSignatureValue;
- OUString m_aSignatureValue;
- bool m_bInX509Certificate;
- OUString m_aX509Certificate;
- bool m_bInMdssiValue;
- OUString m_aMdssiValue;
- bool m_bInSignatureComments;
- OUString m_aSignatureComments;
- bool m_bInX509IssuerName;
- OUString m_aX509IssuerName;
- bool m_bInX509SerialNumber;
- OUString m_aX509SerialNumber;
- bool m_bInCertDigest;
- OUString m_aCertDigest;
- bool m_bInValidSignatureImage;
- OUString m_aValidSignatureImage;
- bool m_bInInvalidSignatureImage;
- OUString m_aInvalidSignatureImage;
- bool m_bInSignatureLineId;
- OUString m_aSignatureLineId;
-
/// Last seen <Reference URI="...">.
OUString m_aReferenceURI;
/// Already called addStreamReference() for this reference.
bool m_bReferenceUnresolved;
XMLSignatureHelper& m_rXMLSignatureHelper;
+ OUString HandleIdAttr(css::uno::Reference<css::xml::sax::XAttributeList> const& xAttrs);
+
public:
explicit OOXMLSecParser(XMLSignatureHelper& rXMLSignatureHelper, XSecController* pXSecController);
virtual ~OOXMLSecParser() override;
commit 42da332e8c853e2f9dacd86e63a8881476f3d648
Author: Samuel Mehrbrodt <samuel.mehrbrodt at allotropia.de>
AuthorDate: Thu Mar 18 11:41:29 2021 +0100
Commit: Thorsten Behrens <thorsten.behrens at allotropia.de>
CommitDate: Thu Apr 15 02:44:53 2021 +0200
tdf#141079 Restore double click behavior for script fields
Change-Id: I5daa730740ea042bdae56b832f2557ec974339b3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112668
Tested-by: Jenkins
Reviewed-by: Samuel Mehrbrodt <samuel.mehrbrodt at allotropia.de>
(cherry picked from commit 5302268de6a33716c7746aa13232746ad2f2b561)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113074
Tested-by: Thorsten Behrens <thorsten.behrens at allotropia.de>
Reviewed-by: Thorsten Behrens <thorsten.behrens at allotropia.de>
diff --git a/sw/qa/extras/layout/data/tdf141079.odt b/sw/qa/extras/layout/data/tdf141079.odt
new file mode 100644
index 000000000000..65dfcb4a296f
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf141079.odt differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index c94811b4d5e7..dd3094ec888d 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -3419,6 +3419,36 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testImageComment)
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5), aPosition.nContent.GetIndex());
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testScriptField)
+{
+ // Test clicking script field inside table ( tdf#141079 )
+ SwDoc* pDoc = createDoc("tdf141079.odt");
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ // Look up layout position which is the first cell in the table
+ SwRootFrame* pRoot = pWrtShell->GetLayout();
+ CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
+ SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
+ CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
+ SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
+ CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
+ SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
+ CPPUNIT_ASSERT(pTextFrame->GetNext()->IsTabFrame());
+ SwFrame* pTable = pTextFrame->GetNext();
+ SwFrame* pRow1 = pTable->GetLower();
+ CPPUNIT_ASSERT(pRow1->GetLower()->IsCellFrame());
+ SwFrame* pCell1 = pRow1->GetLower();
+ CPPUNIT_ASSERT(pCell1->GetLower()->IsTextFrame());
+ SwTextFrame* pCellTextFrame = static_cast<SwTextFrame*>(pCell1->GetLower());
+ const SwRect& rCellRect = pCell1->getFrameArea();
+ Point aPoint = rCellRect.Center();
+ aPoint.setX(aPoint.getX() - rCellRect.Width() / 2);
+ // Ask for the doc model pos of this layout point.
+ SwPosition aPosition(*pCellTextFrame->GetTextNodeForFirstText());
+ pCellTextFrame->GetCursorOfst(&aPosition, aPoint);
+ // Position was 1 without the fix from tdf#141079
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.nContent.GetIndex());
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf64222)
{
createDoc("tdf64222.docx");
diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx
index 5806f06e3b76..6528ffff440e 100644
--- a/sw/source/core/text/itrcrsr.cxx
+++ b/sw/source/core/text/itrcrsr.cxx
@@ -1538,8 +1538,12 @@ TextFrameIndex SwTextCursor::GetCursorOfst( SwPosition *pPos, const Point &rPoin
{
if (pPor->IsPostItsPortion())
{
- // Offset would be nCurrStart + nLength below, do the same for post-it portions.
- nCurrStart += pPor->GetLen();
+ SwPostItsPortion* pPostItsPortion = dynamic_cast<SwPostItsPortion*>(pPor);
+ if (!pPostItsPortion->IsScript()) // tdf#141079
+ {
+ // Offset would be nCurrStart + nLength below, do the same for post-it portions.
+ nCurrStart += pPor->GetLen();
+ }
}
return nCurrStart;
}
More information about the Libreoffice-commits
mailing list