Skip to content

Commit 4865d03

Browse files
Merge commit from fork
* Use correct XPaths and resolve to correct elements * Update xml_security.rb * Block references that resolve to multiple nodes to prevent signature wrapping attacks
1 parent 6e33ed3 commit 4865d03

File tree

1 file changed

+19
-7
lines changed

1 file changed

+19
-7
lines changed

lib/xml_security.rb

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,17 +310,29 @@ def validate_signature(base64_cert, soft = true)
310310
canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
311311
noko_sig_element.remove
312312

313+
# get signed info
314+
signed_info_element = REXML::XPath.first(
315+
sig_element,
316+
"./ds:SignedInfo",
317+
{ "ds" => DSIG }
318+
)
313319
# get inclusive namespaces
314320
inclusive_namespaces = extract_inclusive_namespaces
315321

316322
# check digests
317-
ref = REXML::XPath.first(sig_element, "//ds:Reference", {"ds"=>DSIG})
323+
ref = REXML::XPath.first(signed_info_element, "./ds:Reference", {"ds"=>DSIG})
318324

319-
hashed_element = document.at_xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id })
325+
reference_nodes = document.xpath("//*[@ID=$id]", nil, { 'id' => extract_signed_element_id })
326+
327+
if reference_nodes.length > 1 # ensures no elements with same ID to prevent signature wrapping attack.
328+
return append_error("Digest Mismatch", soft)
329+
end
330+
331+
hashed_element = reference_nodes[0]
320332

321333
canon_algorithm = canon_algorithm REXML::XPath.first(
322-
ref,
323-
'//ds:CanonicalizationMethod',
334+
signed_info_element,
335+
'./ds:CanonicalizationMethod',
324336
{ "ds" => DSIG }
325337
)
326338

@@ -330,13 +342,13 @@ def validate_signature(base64_cert, soft = true)
330342

331343
digest_algorithm = algorithm(REXML::XPath.first(
332344
ref,
333-
"//ds:DigestMethod",
345+
"./ds:DigestMethod",
334346
{ "ds" => DSIG }
335347
))
336348
hash = digest_algorithm.digest(canon_hashed_element)
337349
encoded_digest_value = REXML::XPath.first(
338350
ref,
339-
"//ds:DigestValue",
351+
"./ds:DigestValue",
340352
{ "ds" => DSIG }
341353
)
342354
digest_value = Base64.decode64(OneLogin::RubySaml::Utils.element_text(encoded_digest_value))
@@ -362,7 +374,7 @@ def validate_signature(base64_cert, soft = true)
362374
def process_transforms(ref, canon_algorithm)
363375
transforms = REXML::XPath.match(
364376
ref,
365-
"//ds:Transforms/ds:Transform",
377+
"./ds:Transforms/ds:Transform",
366378
{ "ds" => DSIG }
367379
)
368380

0 commit comments

Comments
 (0)