From: =?utf-8?q?Ferenc_W=C3=A1gner?= <wferi@debian.org>
Date: Tue, 20 Feb 2018 11:23:13 +0100
Subject: CVE-2018-0489 - Fix additional data forgery flaws

These flaws allow for changes to an XML document that do not break a
digital signature but alter the user data passed through to applications
enabling impersonation attacks and exposure of protected information.

https://shibboleth.net/community/advisories/secadv_20180227.txt
https://issues.shibboleth.net/jira/browse/CPPXT-128
---
 xmltooling/AbstractComplexElement.cpp           | 16 +++++++++++++++-
 xmltooling/AbstractSimpleElement.cpp            | 22 ++++++++++++++--------
 xmltooling/io/AbstractXMLObjectUnmarshaller.cpp |  5 +++--
 xmltooling/util/ParserPool.cpp                  |  2 ++
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/xmltooling/AbstractComplexElement.cpp b/xmltooling/AbstractComplexElement.cpp
index a8e68ef..d8d6038 100644
--- a/xmltooling/AbstractComplexElement.cpp
+++ b/xmltooling/AbstractComplexElement.cpp
@@ -102,5 +102,19 @@ void AbstractComplexElement::setTextContent(const XMLCh* value, unsigned int pos
         m_text.push_back(nullptr);
         ++size;
     }
-    m_text[position] = prepareForAssignment(m_text[position], value);
+
+    // Merge if necessary.
+    if (value && *value) {
+        if (!m_text[position] || !*m_text[position]) {
+            m_text[position] = prepareForAssignment(m_text[position], value);
+        }
+        else {
+            XMLSize_t initialLen = XMLString::stringLen(m_text[position]);
+            XMLCh* merged = new XMLCh[initialLen + XMLString::stringLen(value) + 1];
+            auto_arrayptr<XMLCh> janitor(merged);
+            XMLString::copyString(merged, m_text[position]);
+            XMLString::catString(merged + initialLen, value);
+            m_text[position] = prepareForAssignment(m_text[position], merged);
+        }
+    }
 }
diff --git a/xmltooling/AbstractSimpleElement.cpp b/xmltooling/AbstractSimpleElement.cpp
index 5782e3b..9e4d4a2 100644
--- a/xmltooling/AbstractSimpleElement.cpp
+++ b/xmltooling/AbstractSimpleElement.cpp
@@ -77,12 +77,18 @@ void AbstractSimpleElement::setTextContent(const XMLCh* value, unsigned int posi
     if (position > 0)
         throw XMLObjectException("Cannot set text content in simple element at position > 0.");
 
-    // We overwrite the "one" piece of Text content if:
-    //  - the new value is null
-    //  - there is no existing value
-    //  - the old value is all whitespace
-    // If there's a non-whitespace value set, we leave it alone unless we're clearing it with a null.
-
-    if (!value || !m_value || XMLChar1_0::isAllSpaces(m_value, XMLString::stringLen(m_value)))
-        m_value=prepareForAssignment(m_value, value);
+    // Merge if necessary.
+    if (value && *value) {
+        if (!m_value || !*m_value) {
+            m_value = prepareForAssignment(m_value, value);
+        }
+        else {
+            XMLSize_t initialLen = XMLString::stringLen(m_value);
+            XMLCh* merged = new XMLCh[initialLen + XMLString::stringLen(value) + 1];
+            auto_arrayptr<XMLCh> janitor(merged);
+            XMLString::copyString(merged, m_value);
+            XMLString::catString(merged + initialLen, value);
+            m_value = prepareForAssignment(m_value, merged);
+        }
+    }
 }
diff --git a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
index 487348e..eac4187 100644
--- a/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
+++ b/xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
@@ -206,8 +206,9 @@ void AbstractXMLObjectUnmarshaller::unmarshallContent(const DOMElement* domEleme
         else if (childNode->getNodeType() == DOMNode::TEXT_NODE || childNode->getNodeType() == DOMNode::CDATA_SECTION_NODE) {
             m_log.debug("processing text content at position (%d)", position);
             setTextContent(childNode->getNodeValue(), position);
-        } else if (childNode->getNodeType() == DOMNode::ENTITY_REFERENCE_NODE || childNode->getNodeType() == DOMNode::ENTITY_NODE) {
-            throw UnmarshallingException("Unmarshaller found Entity/Reference node.");
+        }
+        else if (childNode->getNodeType() != DOMNode::ATTRIBUTE_NODE) {
+            throw UnmarshallingException("Unmarshaller found unsupported node type.");
         }
         
         childNode = childNode->getNextSibling();
diff --git a/xmltooling/util/ParserPool.cpp b/xmltooling/util/ParserPool.cpp
index d2ba3a1..7c6a7a6 100644
--- a/xmltooling/util/ParserPool.cpp
+++ b/xmltooling/util/ParserPool.cpp
@@ -417,6 +417,7 @@ DOMLSParser* ParserPool::createBuilder()
     parser->getDomConfig()->setParameter(XMLUni::fgDOMResourceResolver, dynamic_cast<DOMLSResourceResolver*>(this));
     parser->getDomConfig()->setParameter(XMLUni::fgXercesSecurityManager, m_security.get());
     parser->getDomConfig()->setParameter(XMLUni::fgDOMDisallowDoctype, true);
+    parser->getDomConfig()->setParameter(XMLUni::fgDOMComments, false);
     return parser;
 }
 
@@ -463,6 +464,7 @@ DOMBuilder* ParserPool::createBuilder()
     parser->setProperty(XMLUni::fgXercesSecurityManager, m_security.get());
     parser->setFeature(XMLUni::fgXercesUserAdoptsDOMDocument, true);
     parser->setFeature(XMLUni::fgXercesDisableDefaultEntityResolution, true);
+    parser->setFeature(XMLUni::fgDOMComments, false);
     parser->setEntityResolver(this);
     return parser;
 }
