Skip to content

Commit e373424

Browse files
bartonjsm0savcsjones
authored
Fixing SignedXml.CheckSignature for enveloped signature with #xpointer(/) Reference
This additionally improves support for URI-less Reference elements. Co-authored-by: Samo Prelog <samo@prelog.io> Co-authored-by: Kevin Jones <kevin@vcsjones.com>
1 parent c412efb commit e373424

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
55
<NoWarn>$(NoWarn);CA1850</NoWarn> <!-- CA1850 suppressed due to multitargeting -->
66
<IsPackable>true</IsPackable>
7+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
8+
<ServicingVersion>1</ServicingVersion>
79
<PackageDescription>Provides classes to support the creation and validation of XML digital signatures. The classes in this namespace implement the World Wide Web Consortium Recommendation, "XML-Signature Syntax and Processing", described at http://www.w3.org/TR/xmldsig-core/.
810

911
Commonly Used Types:

src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs

+19-6
Original file line numberDiff line numberDiff line change
@@ -266,18 +266,31 @@ public void LoadXml(XmlElement value)
266266
// let the transform read the children of the transformElement for data
267267
transform.LoadInnerXml(transformElement.ChildNodes);
268268
// Hack! this is done to get around the lack of here() function support in XPath
269-
if (transform is XmlDsigEnvelopedSignatureTransform
270-
&& _uri != null && (_uri.Length == 0 || _uri[0] == '#'))
269+
if (transform is XmlDsigEnvelopedSignatureTransform)
271270
{
272271
// Walk back to the Signature tag. Find the nearest signature ancestor
273272
// Signature-->SignedInfo-->Reference-->Transforms-->Transform
274273
XmlNode? signatureTag = transformElement.SelectSingleNode("ancestor::ds:Signature[1]", nsm);
275274

276275
// Resolve the reference to get starting point for position calculation.
277-
XmlNode? referenceTarget =
278-
_uri.Length == 0
279-
? transformElement.OwnerDocument
280-
: SignedXml!.GetIdElement(transformElement.OwnerDocument, Utils.GetIdFromLocalUri(_uri, out bool _));
276+
// This needs to match the way CalculateSignature resolves URI references.
277+
XmlNode? referenceTarget = null;
278+
if (_uri == null || _uri.Length == 0)
279+
{
280+
referenceTarget = transformElement.OwnerDocument;
281+
}
282+
else if (_uri[0] == '#')
283+
{
284+
string idref = Utils.ExtractIdFromLocalUri(_uri);
285+
if (idref == "xpointer(/)")
286+
{
287+
referenceTarget = transformElement.OwnerDocument;
288+
}
289+
else
290+
{
291+
referenceTarget = SignedXml!.GetIdElement(transformElement.OwnerDocument, idref);
292+
}
293+
}
281294

282295
XmlNodeList? signatureList = referenceTarget?.SelectNodes(".//ds:Signature", nsm);
283296
if (signatureList != null)

src/libraries/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs

+41
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
1010
// Copyright (C) 2004-2005, 2008 Novell, Inc (http://www.novell.com)
1111

12+
using System.Collections.Generic;
1213
using System.Globalization;
1314
using System.IO;
1415
using System.Net;
@@ -1993,5 +1994,45 @@ public void CheckSignatureHandlesIncorrectOrTamperedReferenceWithMultipleEnvelop
19931994

19941995
Assert.False(subject.CheckSignature());
19951996
}
1997+
1998+
public static object[][] EnvelopedSignatureWithRootXpointerReference = new object[][]
1999+
{
2000+
new object[] { true, """<?xml version="1.0" encoding="UTF-8"?><hello><world>Hi</world><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#xpointer(/)"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>SVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=</DigestValue></Reference></SignedInfo><SignatureValue>dqcBmS1ZvDJNhmCEgobpAb+A2XaiuB69dfGIhisZvqoxaWqAqv/0w49jp38+usJ5t3wcq3aMC631QE8iln+lHWrarojDMDWLa00isv3oE3q9UgOIV9e6MUSoRTTvQkmlK/LSYV9T/SKx6h03vLLcIkUMXaTkC/n2kthlJTGkLbU=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>t6qV1iTlkCPoaIeOTvnDczQv5pytUxMoyNXws5vaMQYxfJMKos47dvmiLtfWUDLYXFX3Yf/JMC14plJw2JA5jLrlHLnZj/vCjRtXckmWW/wGYewXUqrgR1CytStUeQKj9mNsi76erukua10UhzIrWG+H6YQ/qS4AMMJZU6jBvO0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></hello>""" },
2001+
new object[] { false, """<?xml version="1.0" encoding="UTF-8"?><hello>Tempered world<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#xpointer(/)"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>SVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=</DigestValue></Reference></SignedInfo><SignatureValue>dqcBmS1ZvDJNhmCEgobpAb+A2XaiuB69dfGIhisZvqoxaWqAqv/0w49jp38+usJ5t3wcq3aMC631QE8iln+lHWrarojDMDWLa00isv3oE3q9UgOIV9e6MUSoRTTvQkmlK/LSYV9T/SKx6h03vLLcIkUMXaTkC/n2kthlJTGkLbU=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>t6qV1iTlkCPoaIeOTvnDczQv5pytUxMoyNXws5vaMQYxfJMKos47dvmiLtfWUDLYXFX3Yf/JMC14plJw2JA5jLrlHLnZj/vCjRtXckmWW/wGYewXUqrgR1CytStUeQKj9mNsi76erukua10UhzIrWG+H6YQ/qS4AMMJZU6jBvO0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></hello>""" },
2002+
};
2003+
2004+
[Theory]
2005+
[MemberData(nameof(EnvelopedSignatureWithRootXpointerReference))]
2006+
public void CheckSignatureHandlesEnvelopedSignatureWithRootXpointerReference(bool isValid, string xml)
2007+
{
2008+
XmlDocument xmlDoc = new ();
2009+
xmlDoc.LoadXml(xml);
2010+
SignedXml signedXml = new (xmlDoc);
2011+
signedXml.LoadXml(xmlDoc.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl)[0] as XmlElement);
2012+
2013+
Assert.Equal(isValid, signedXml.CheckSignature());
2014+
}
2015+
2016+
2017+
public static object[][] EnvelopedSignatureWithEmptyReference = new object[][]
2018+
{
2019+
new object[] { true, """<?xml version="1.0" encoding="UTF-8"?><hello><world>Hi</world><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>SVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=</DigestValue></Reference></SignedInfo><SignatureValue>CiB9jgIS7+Wq+lpyzCGsBZQcQ2BxqQuEU9VCvb3Li5jMtjwRV1bMO+4Wfnb4VWhEtEUq6NdiVGXhC1xvtVLnnLDX7CD/jG6NvM1Yd0/rf0UUceBhzYLFE9HLsopsBmmm3t8FO6ZtRr1QqKM0XDaQleGK9vYd2m2Jq8OR3r/w4OY=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>vcM1wQVmLB9DwdnAym8l8nw63/HlTVzgTDhIwNzWPhsPE/qr2wlK4TEQ3rjU+RAdNytfFNCnuuh75ZVMjAWCV9h6VDlp0DOvBhb6GenhymtTAdJJKzBXKJP6mNPga9cPOP31IZ36Ui00G3fjBBPrHa7nStludgL9Wi0dBU28DjU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></hello>""" },
2020+
new object[] { false, """<?xml version="1.0" encoding="UTF-8"?><hello><WORLD>HI</WORLD><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>SVaCE5w9iLXTVYTKP1t/yjjmPXvWovMYpgljGgpgz2Y=</DigestValue></Reference></SignedInfo><SignatureValue>CiB9jgIS7+Wq+lpyzCGsBZQcQ2BxqQuEU9VCvb3Li5jMtjwRV1bMO+4Wfnb4VWhEtEUq6NdiVGXhC1xvtVLnnLDX7CD/jG6NvM1Yd0/rf0UUceBhzYLFE9HLsopsBmmm3t8FO6ZtRr1QqKM0XDaQleGK9vYd2m2Jq8OR3r/w4OY=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>vcM1wQVmLB9DwdnAym8l8nw63/HlTVzgTDhIwNzWPhsPE/qr2wlK4TEQ3rjU+RAdNytfFNCnuuh75ZVMjAWCV9h6VDlp0DOvBhb6GenhymtTAdJJKzBXKJP6mNPga9cPOP31IZ36Ui00G3fjBBPrHa7nStludgL9Wi0dBU28DjU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></hello>""" },
2021+
};
2022+
2023+
[Theory]
2024+
[MemberData(nameof(EnvelopedSignatureWithEmptyReference))]
2025+
public void CheckSignatureHandlesEnvelopedSignatureWithEmptyReference(bool isValid, string xml)
2026+
{
2027+
XmlDocument xmlDoc = new ();
2028+
xmlDoc.LoadXml(xml);
2029+
SignedXml signedXml = new (xmlDoc);
2030+
signedXml.LoadXml(xmlDoc.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl)[0] as XmlElement);
2031+
2032+
// without this, CheckSignature throws
2033+
((Reference)signedXml.SignedInfo.References[0]).TransformChain[0].LoadInput(xmlDoc);
2034+
2035+
Assert.Equal(isValid, signedXml.CheckSignature());
2036+
}
19962037
}
19972038
}

0 commit comments

Comments
 (0)