Skip to content

Commit a7b1f2e

Browse files
committed
Use correct XPaths and resolve to correct elements. Block references that resolve to multiple nodes to prevent signature wrapping attacks
1 parent 626140b commit a7b1f2e

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

lib/ruby_saml/xml/signed_document.rb

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,30 @@ def validate_signature(base64_cert, soft = true)
129129
canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
130130
noko_sig_element.remove
131131

132+
# get signed info
133+
signed_info_element = REXML::XPath.first(
134+
sig_element,
135+
"./ds:SignedInfo",
136+
{ "ds" => DSIG }
137+
)
138+
132139
# get inclusive namespaces
133140
inclusive_namespaces = extract_inclusive_namespaces
134141

135142
# check digests
136-
ref = REXML::XPath.first(sig_element, '//ds:Reference', {'ds'=>DSIG})
143+
ref = REXML::XPath.first(signed_info_element, "./ds:Reference", {"ds"=>DSIG})
137144

138-
hashed_element = document.at_xpath('//*[@ID=$id]', nil, { 'id' => extract_signed_element_id })
145+
reference_nodes = document.xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id })
146+
147+
if reference_nodes.length > 1 # ensures no elements with same ID to prevent signature wrapping attack.
148+
return append_error("Digest mismatch. Duplicated ID found", soft)
149+
end
150+
151+
hashed_element = reference_nodes[0]
139152

140153
canon_algorithm = canon_algorithm REXML::XPath.first(
141-
ref,
142-
'//ds:CanonicalizationMethod',
154+
signed_info_element,
155+
'./ds:CanonicalizationMethod',
143156
{ 'ds' => DSIG }
144157
)
145158

@@ -155,7 +168,7 @@ def validate_signature(base64_cert, soft = true)
155168
hash = digest_algorithm.digest(canon_hashed_element)
156169
encoded_digest_value = REXML::XPath.first(
157170
ref,
158-
'//ds:DigestValue',
171+
'./ds:DigestValue',
159172
{ 'ds' => DSIG }
160173
)
161174
digest_value = Base64.decode64(RubySaml::Utils.element_text(encoded_digest_value))
@@ -181,7 +194,7 @@ def validate_signature(base64_cert, soft = true)
181194
def process_transforms(ref, canon_algorithm)
182195
transforms = REXML::XPath.match(
183196
ref,
184-
'//ds:Transforms/ds:Transform',
197+
'./ds:Transforms/ds:Transform',
185198
{ 'ds' => DSIG }
186199
)
187200

0 commit comments

Comments
 (0)