Skip to content

Commit f9651c7

Browse files
committed
Move utilities to the place where they belong
1 parent 6f81ec6 commit f9651c7

File tree

4 files changed

+121
-139
lines changed

4 files changed

+121
-139
lines changed

src/Utils/XML.php

Lines changed: 0 additions & 133 deletions
This file was deleted.

src/XML/CanonicalizableElementTrait.php

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
namespace SimpleSAML\XMLSecurity\XML;
66

77
use DOMElement;
8-
use SimpleSAML\XMLSecurity\Utils\XML;
8+
use SimpleSAML\Assert\Assert;
9+
use SimpleSAML\XMLSecurity\Constants as C;
10+
use SimpleSAML\XMLSecurity\Exception\ReferenceValidationFailedException;
11+
use SimpleSAML\XMLSecurity\Utils\XPath;
12+
use SimpleSAML\XMLSecurity\XML\ds\Transforms;
13+
use SimpleSAML\XPath\Constants as XPATH_C;
914

1015
/**
1116
* A trait implementing the CanonicalizableElementInterface.
@@ -25,6 +30,64 @@ trait CanonicalizableElementTrait
2530
abstract protected function getOriginalXML(): DOMElement;
2631

2732

33+
/**
34+
* Canonicalize any given node.
35+
*
36+
* @param \DOMElement $element The DOM element that needs canonicalization.
37+
* @param string $c14nMethod The identifier of the canonicalization algorithm to use.
38+
* See \SimpleSAML\XMLSecurity\Constants.
39+
* @param string[]|null $xpaths An array of xpaths to filter the nodes by. Defaults to null (no filters).
40+
* @param string[]|null $prefixes An array of namespace prefixes to filter the nodes by.
41+
* Defaults to null (no filters).
42+
*
43+
* @return string The canonical representation of the given DOM node, according to the algorithm requested.
44+
*/
45+
public function canonicalizeData(
46+
DOMElement $element,
47+
string $c14nMethod,
48+
?array $xpaths = null,
49+
?array $prefixes = null,
50+
): string {
51+
$withComments = match ($c14nMethod) {
52+
C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_INCLUSIVE_WITH_COMMENTS => true,
53+
default => false,
54+
};
55+
$exclusive = match ($c14nMethod) {
56+
C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS => true,
57+
default => false,
58+
};
59+
60+
if (
61+
is_null($xpaths)
62+
&& ($element->ownerDocument !== null)
63+
&& ($element->ownerDocument->documentElement !== null)
64+
&& $element->isSameNode($element->ownerDocument->documentElement)
65+
) {
66+
// check for any PI or comments as they would have been excluded
67+
$current = $element;
68+
for ($refNode = $current->previousSibling; $refNode !== null; $current = $refNode) {
69+
if (
70+
(($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
71+
|| $refNode->nodeType === XML_PI_NODE
72+
) {
73+
break;
74+
}
75+
}
76+
77+
if ($refNode === null) {
78+
$element = $element->ownerDocument;
79+
}
80+
}
81+
82+
$ret = $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
83+
if ($ret === false) {
84+
// GHSA-h25p-2wxc-6584
85+
throw new CanonicalizationFailedException();
86+
}
87+
return $ret;
88+
}
89+
90+
2891
/**
2992
* Get the canonical (string) representation of this object.
3093
*
@@ -39,7 +102,61 @@ abstract protected function getOriginalXML(): DOMElement;
39102
#[\NoDiscard]
40103
public function canonicalize(string $method, ?array $xpaths = null, ?array $prefixes = null): string
41104
{
42-
return XML::canonicalizeData($this->getOriginalXML(), $method, $xpaths, $prefixes);
105+
return $this->canonicalizeData($this->getOriginalXML(), $method, $xpaths, $prefixes);
106+
}
107+
108+
109+
/**
110+
* Process all transforms specified by a given Reference element.
111+
*
112+
* @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
113+
* @param \DOMElement $data The data referenced.
114+
*
115+
* @return string The canonicalized data after applying all transforms specified by $ref.
116+
*
117+
* @see http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
118+
*/
119+
public function processTransforms(
120+
Transforms $transforms,
121+
DOMElement $data,
122+
): string {
123+
$canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
124+
$arXPath = null;
125+
$prefixList = null;
126+
foreach ($transforms->getTransform() as $transform) {
127+
$canonicalMethod = $transform->getAlgorithm()->getValue();
128+
switch ($canonicalMethod) {
129+
case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
130+
case C::C14N_EXCLUSIVE_WITH_COMMENTS:
131+
$inclusiveNamespaces = $transform->getInclusiveNamespaces();
132+
if ($inclusiveNamespaces !== null) {
133+
$prefixes = $inclusiveNamespaces->getPrefixes();
134+
if ($prefixes !== null) {
135+
$prefixList = array_map('strval', $prefixes->toArray());
136+
}
137+
}
138+
break;
139+
case XPATH_C::XPATH10_URI:
140+
$xpath = $transform->getXPath();
141+
if ($xpath !== null) {
142+
$arXPath = [];
143+
$xpathValue = $xpath->getContent()->getValue();
144+
$arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpathValue . ']';
145+
146+
// $arXpath['namespaces'] = $xpath->getNamespaces();
147+
// TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
148+
// $nslist = $xp->query('./namespace::*', $node);
149+
// foreach ($nslist as $nsnode) {
150+
// if ($nsnode->localName != "xml") {
151+
// $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
152+
// }
153+
// }
154+
}
155+
break;
156+
}
157+
}
158+
159+
return $this->canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
43160
}
44161

45162

src/XML/SignableElementTrait.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use SimpleSAML\XMLSecurity\Exception\RuntimeException;
1616
use SimpleSAML\XMLSecurity\Exception\UnsupportedAlgorithmException;
1717
use SimpleSAML\XMLSecurity\Type\DigestValue as DigestValueType;
18-
use SimpleSAML\XMLSecurity\Utils\XML;
1918
use SimpleSAML\XMLSecurity\XML\ds\CanonicalizationMethod;
2019
use SimpleSAML\XMLSecurity\XML\ds\DigestMethod;
2120
use SimpleSAML\XMLSecurity\XML\ds\DigestValue;
@@ -188,7 +187,7 @@ protected function doSign(DOMElement $xml): DOMElement
188187
),
189188
]);
190189

191-
$canonicalDocument = XML::processTransforms($transforms, $xml);
190+
$canonicalDocument = $this->processTransforms($transforms, $xml);
192191

193192
$signedInfo = new SignedInfo(
194193
new CanonicalizationMethod(

src/XML/SignedElementTrait.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
use SimpleSAML\XMLSecurity\Exception\SignatureVerificationFailedException;
2121
use SimpleSAML\XMLSecurity\Key;
2222
use SimpleSAML\XMLSecurity\Key\KeyInterface;
23-
use SimpleSAML\XMLSecurity\Utils\XML;
2423
use SimpleSAML\XMLSecurity\Utils\XPath;
2524
use SimpleSAML\XMLSecurity\XML\ds\Reference;
2625
use SimpleSAML\XMLSecurity\XML\ds\Signature;
@@ -157,7 +156,7 @@ private function validateReference(SignedInfo $signedInfo): SignedElementInterfa
157156
Assert::maxCount($sigNode, 1, 'More than one signature found in object.', TooManyElementsException::class);
158157

159158
$doc->documentElement->removeChild($sigNode[0]);
160-
$data = XML::processTransforms($reference->getTransforms(), $doc->documentElement);
159+
$data = $this->processTransforms($reference->getTransforms(), $doc->documentElement);
161160
$algo = $reference->getDigestMethod()->getAlgorithm()->getValue();
162161
Assert::keyExists(
163162
C::$DIGEST_ALGORITHMS,

0 commit comments

Comments
 (0)