CVE-2019-3465: Improper Verification of Cryptographic Signature (CWE-347)
value: Rob Richards XmlSecLibs, all versions prior to v3.0.3, as used for example by SimpleSAMLphp, performed incorrect validation of cryptographic signatures in XML messages, allowing an authenticated attacker to impersonate others or elevate privileges by creating a crafted XML message.
CWE description: The product does not verify, or incorrectly verifies, the cryptographic signature for data.
CVSS v3 base score: 8.8
Published: 2019-11-07T20:15Z
Repository: https://github.com/robrichards/xmlseclibs
Language: PHP
Files changed: CHANGELOG.txt, LICENSE, src/XMLSecurityDSig.php, xmlseclibs.php
Commit date: 2019-11-05 06:44:22 -0500
Commit message: Release 3.0.4. Security release for CVE-2019-3465

Diff: diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 76220cb..faaf61c 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,8 +1,13 @@
 xmlseclibs.php
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-??, ??? 2018, 3.0.4-dev
+06, Nov 2019, 3.0.4
+Security Improvements:
+- Insure only a single SignedInfo element exists within a signature during 
+  verification. Refs CVE-2019-3465.
+Bug Fixes:
+- Fix variable casing.
 
 15, Nov 2018, 3.0.3
 Bug Fixes:
 - Fix casing of class name. (Willem Stuursma-Ruwen)
 - Fix Xpath casing. (Tim van Dijen)
diff --git a/LICENSE b/LICENSE
index 54b1e87..4fe5e5f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
-Copyright (c) 2007-2018, Robert Richards <rrichards@cdatazone.org>.
+Copyright (c) 2007-2019, Robert Richards <rrichards@cdatazone.org>.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php
index ada217b..c9063d0 100644
--- a/src/XMLSecurityDSig.php
+++ b/src/XMLSecurityDSig.php
@@ -192,10 +192,15 @@ class XMLSecurityDSig
             $xpath = new DOMXPath($doc);
             $xpath->registerNamespace('secdsig', self::XMLDSIGNS);
             $query = ".//secdsig:Signature";
             $nodeset = $xpath->query($query, $objDoc);
             $this->sigNode = $nodeset->item($pos);
+            $query = "./secdsig:SignedInfo";
+            $nodeset = $xpath->query($query, $this->sigNode);
+            if ($nodeset->length > 1) {
+                throw new Exception("Invalid structure - Too many SignedInfo elements found");
+            }
             return $this->sigNode;
         }
         return null;
     }
 
@@ -301,10 +306,13 @@ class XMLSecurityDSig
         $canonicalmethod = null;
         if ($doc) {
             $xpath = $this->getXPathObj();
             $query = "./secdsig:SignedInfo";
             $nodeset = $xpath->query($query, $this->sigNode);
+            if ($nodeset->length > 1) {
+                throw new Exception("Invalid structure - Too many SignedInfo elements found");
+            }
             if ($signInfoNode = $nodeset->item(0)) {
                 $query = "./secdsig:CanonicalizationMethod";
                 $nodeset = $xpath->query($query, $signInfoNode);
                 if ($canonNode = $nodeset->item(0)) {
                     $canonicalmethod = $canonNode->getAttribute('Algorithm');
@@ -438,11 +446,11 @@ class XMLSecurityDSig
                     $node = $transform->firstChild;
                     while ($node) {
                         if ($node->localName == 'XPath') {
                             $arXPath = array();
                             $arXPath['query'] = '(.//. | .//@* | .//namespace::*)['.$node->nodeValue.']';
-                            $arXpath['namespaces'] = array();
+                            $arXPath['namespaces'] = array();
                             $nslist = $xpath->query('./namespace::*', $node);
                             foreach ($nslist AS $nsnode) {
                                 if ($nsnode->localName != "xml") {
                                     $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
                                 }
@@ -552,11 +560,11 @@ class XMLSecurityDSig
     public function getRefIDs()
     {
         $refids = array();
 
         $xpath = $this->getXPathObj();
-        $query = "./secdsig:SignedInfo/secdsig:Reference";
+        $query = "./secdsig:SignedInfo[1]/secdsig:Reference";
         $nodeset = $xpath->query($query, $this->sigNode);
         if ($nodeset->length == 0) {
             throw new Exception("Reference nodes not found");
         }
         foreach ($nodeset AS $refNode) {
@@ -576,11 +584,11 @@ class XMLSecurityDSig
             if ($this->sigNode->parentNode != null) {
                 $this->sigNode->parentNode->removeChild($this->sigNode);
             }
         }
         $xpath = $this->getXPathObj();
-        $query = "./secdsig:SignedInfo/secdsig:Reference";
+        $query = "./secdsig:SignedInfo[1]/secdsig:Reference";
         $nodeset = $xpath->query($query, $this->sigNode);
         if ($nodeset->length == 0) {
             throw new Exception("Reference nodes not found");
         }
 
diff --git a/xmlseclibs.php b/xmlseclibs.php
index 1e6eec7..4470dab 100644
--- a/xmlseclibs.php
+++ b/xmlseclibs.php
@@ -35,11 +35,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * @author    Robert Richards <rrichards@cdatazone.org>
  * @copyright 2007-2019 Robert Richards <rrichards@cdatazone.org>
  * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
- * @version   3.0.4-dev
+ * @version   3.0.4
  */
 
 $xmlseclibs_srcdir = dirname(__FILE__) . '/src/';
 require $xmlseclibs_srcdir . '/XMLSecurityKey.php';
 require $xmlseclibs_srcdir . '/XMLSecurityDSig.php';

Vulnerable code: ??, ??? 2018, 3.0.4-dev
Copyright (c) 2007-2018, Robert Richards <rrichards@cdatazone.org>.
                            $arXpath['namespaces'] = array();
        $query = "./secdsig:SignedInfo/secdsig:Reference";
        $query = "./secdsig:SignedInfo/secdsig:Reference";
 * @version   3.0.4-dev
Fixed code: 06, Nov 2019, 3.0.4
Security Improvements:
- Insure only a single SignedInfo element exists within a signature during 
  verification. Refs CVE-2019-3465.
Bug Fixes:
- Fix variable casing.
Copyright (c) 2007-2019, Robert Richards <rrichards@cdatazone.org>.
            $query = "./secdsig:SignedInfo";
            $nodeset = $xpath->query($query, $this->sigNode);
            if ($nodeset->length > 1) {
                throw new Exception("Invalid structure - Too many SignedInfo elements found");
            }
            if ($nodeset->length > 1) {
                throw new Exception("Invalid structure - Too many SignedInfo elements found");
            }
                            $arXPath['namespaces'] = array();
        $query = "./secdsig:SignedInfo[1]/secdsig:Reference";
        $query = "./secdsig:SignedInfo[1]/secdsig:Reference";
 * @version   3.0.4