diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs
index 001aaf26a21aee..ec6e6cabc2cdfa 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs
@@ -266,18 +266,31 @@ public void LoadXml(XmlElement value)
// let the transform read the children of the transformElement for data
transform.LoadInnerXml(transformElement.ChildNodes);
// Hack! this is done to get around the lack of here() function support in XPath
- if (transform is XmlDsigEnvelopedSignatureTransform
- && _uri != null && (_uri.Length == 0 || _uri[0] == '#'))
+ if (transform is XmlDsigEnvelopedSignatureTransform)
{
// Walk back to the Signature tag. Find the nearest signature ancestor
// Signature-->SignedInfo-->Reference-->Transforms-->Transform
XmlNode? signatureTag = transformElement.SelectSingleNode("ancestor::ds:Signature[1]", nsm);
// Resolve the reference to get starting point for position calculation.
- XmlNode? referenceTarget =
- _uri.Length == 0
- ? transformElement.OwnerDocument
- : SignedXml!.GetIdElement(transformElement.OwnerDocument, Utils.GetIdFromLocalUri(_uri, out bool _));
+ // This needs to match the way CalculateSignature resolves URI references.
+ XmlNode? referenceTarget = null;
+ if (_uri == null || _uri.Length == 0)
+ {
+ referenceTarget = transformElement.OwnerDocument;
+ }
+ else if (_uri[0] == '#')
+ {
+ string idref = Utils.ExtractIdFromLocalUri(_uri);
+ if (idref == "xpointer(/)")
+ {
+ referenceTarget = transformElement.OwnerDocument;
+ }
+ else
+ {
+ referenceTarget = SignedXml!.GetIdElement(transformElement.OwnerDocument, idref);
+ }
+ }
XmlNodeList? signatureList = referenceTarget?.SelectNodes(".//ds:Signature", nsm);
if (signatureList != null)
diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs b/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
index 3db8c44aed8270..bd22c5b835eed8 100644
--- a/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
@@ -9,6 +9,7 @@
// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004-2005, 2008 Novell, Inc (http://www.novell.com)
+using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
@@ -1993,5 +1994,45 @@ public void CheckSignatureHandlesIncorrectOrTamperedReferenceWithMultipleEnvelop
Assert.False(subject.CheckSignature());
}
+
+ public static object[][] EnvelopedSignatureWithRootXpointerReference = new object[][]
+ {
+ new object[] { true, """HiSVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=dqcBmS1ZvDJNhmCEgobpAb+A2XaiuB69dfGIhisZvqoxaWqAqv/0w49jp38+usJ5t3wcq3aMC631QE8iln+lHWrarojDMDWLa00isv3oE3q9UgOIV9e6MUSoRTTvQkmlK/LSYV9T/SKx6h03vLLcIkUMXaTkC/n2kthlJTGkLbU=t6qV1iTlkCPoaIeOTvnDczQv5pytUxMoyNXws5vaMQYxfJMKos47dvmiLtfWUDLYXFX3Yf/JMC14plJw2JA5jLrlHLnZj/vCjRtXckmWW/wGYewXUqrgR1CytStUeQKj9mNsi76erukua10UhzIrWG+H6YQ/qS4AMMJZU6jBvO0=AQAB""" },
+ new object[] { false, """Tempered worldSVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=dqcBmS1ZvDJNhmCEgobpAb+A2XaiuB69dfGIhisZvqoxaWqAqv/0w49jp38+usJ5t3wcq3aMC631QE8iln+lHWrarojDMDWLa00isv3oE3q9UgOIV9e6MUSoRTTvQkmlK/LSYV9T/SKx6h03vLLcIkUMXaTkC/n2kthlJTGkLbU=t6qV1iTlkCPoaIeOTvnDczQv5pytUxMoyNXws5vaMQYxfJMKos47dvmiLtfWUDLYXFX3Yf/JMC14plJw2JA5jLrlHLnZj/vCjRtXckmWW/wGYewXUqrgR1CytStUeQKj9mNsi76erukua10UhzIrWG+H6YQ/qS4AMMJZU6jBvO0=AQAB""" },
+ };
+
+ [Theory]
+ [MemberData(nameof(EnvelopedSignatureWithRootXpointerReference))]
+ public void CheckSignatureHandlesEnvelopedSignatureWithRootXpointerReference(bool isValid, string xml)
+ {
+ XmlDocument xmlDoc = new ();
+ xmlDoc.LoadXml(xml);
+ SignedXml signedXml = new (xmlDoc);
+ signedXml.LoadXml(xmlDoc.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl)[0] as XmlElement);
+
+ Assert.Equal(isValid, signedXml.CheckSignature());
+ }
+
+
+ public static object[][] EnvelopedSignatureWithEmptyReference = new object[][]
+ {
+ new object[] { true, """HiSVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=CiB9jgIS7+Wq+lpyzCGsBZQcQ2BxqQuEU9VCvb3Li5jMtjwRV1bMO+4Wfnb4VWhEtEUq6NdiVGXhC1xvtVLnnLDX7CD/jG6NvM1Yd0/rf0UUceBhzYLFE9HLsopsBmmm3t8FO6ZtRr1QqKM0XDaQleGK9vYd2m2Jq8OR3r/w4OY=vcM1wQVmLB9DwdnAym8l8nw63/HlTVzgTDhIwNzWPhsPE/qr2wlK4TEQ3rjU+RAdNytfFNCnuuh75ZVMjAWCV9h6VDlp0DOvBhb6GenhymtTAdJJKzBXKJP6mNPga9cPOP31IZ36Ui00G3fjBBPrHa7nStludgL9Wi0dBU28DjU=AQAB""" },
+ new object[] { false, """HISVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=CiB9jgIS7+Wq+lpyzCGsBZQcQ2BxqQuEU9VCvb3Li5jMtjwRV1bMO+4Wfnb4VWhEtEUq6NdiVGXhC1xvtVLnnLDX7CD/jG6NvM1Yd0/rf0UUceBhzYLFE9HLsopsBmmm3t8FO6ZtRr1QqKM0XDaQleGK9vYd2m2Jq8OR3r/w4OY=vcM1wQVmLB9DwdnAym8l8nw63/HlTVzgTDhIwNzWPhsPE/qr2wlK4TEQ3rjU+RAdNytfFNCnuuh75ZVMjAWCV9h6VDlp0DOvBhb6GenhymtTAdJJKzBXKJP6mNPga9cPOP31IZ36Ui00G3fjBBPrHa7nStludgL9Wi0dBU28DjU=AQAB""" },
+ };
+
+ [Theory]
+ [MemberData(nameof(EnvelopedSignatureWithEmptyReference))]
+ public void CheckSignatureHandlesEnvelopedSignatureWithEmptyReference(bool isValid, string xml)
+ {
+ XmlDocument xmlDoc = new ();
+ xmlDoc.LoadXml(xml);
+ SignedXml signedXml = new (xmlDoc);
+ signedXml.LoadXml(xmlDoc.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl)[0] as XmlElement);
+
+ // without this, CheckSignature throws
+ ((Reference)signedXml.SignedInfo.References[0]).TransformChain[0].LoadInput(xmlDoc);
+
+ Assert.Equal(isValid, signedXml.CheckSignature());
+ }
}
}