Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 644880b

Browse files
Forbid XML external entity resolution in crypto APIs
1 parent a6ab07a commit 644880b

File tree

6 files changed

+157
-5
lines changed

6 files changed

+157
-5
lines changed

pkg/Microsoft.Private.PackageBaseline/packageIndex.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5108,13 +5108,14 @@
51085108
"4.6.0",
51095109
"4.7.0"
51105110
],
5111-
"BaselineVersion": "4.7.0",
5111+
"BaselineVersion": "4.7.1",
51125112
"InboxOn": {},
51135113
"AssemblyVersionInPackageVersion": {
51145114
"4.0.0.0": "4.4.0",
51155115
"4.0.1.0": "4.5.0",
51165116
"4.0.2.0": "4.6.0",
5117-
"4.0.3.0": "4.7.0"
5117+
"4.0.3.0": "4.7.0",
5118+
"4.0.3.1": "4.7.1"
51185119
}
51195120
},
51205121
"System.Security.Permissions": {
@@ -6661,4 +6662,4 @@
66616662
"System.Xml.XDocument"
66626663
]
66636664
}
6664-
}
6665+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<Project>
22
<Import Project="..\Directory.Build.props" />
33
<PropertyGroup>
4-
<AssemblyVersion>4.0.3.0</AssemblyVersion>
4+
<AssemblyVersion>4.0.3.1</AssemblyVersion>
5+
<PackageVersion>4.7.1</PackageVersion>
56
<StrongNameKeyId>Open</StrongNameKeyId>
67
</PropertyGroup>
78
</Project>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<AssemblyName>System.Security.Cryptography.Xml</AssemblyName>
44
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -77,6 +77,7 @@
7777
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXPathTransform.cs" />
7878
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXsltTransform.cs" />
7979
<Compile Include="System\Security\Cryptography\Xml\XmlLicenseTransform.cs" />
80+
<Compile Include="System\Security\Cryptography\Xml\XmlSecureResolver.cs" />
8081
<Compile Include="System\Security\Cryptography\Xml\CryptoHelpers.cs" />
8182
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SignatureDescription.cs" />
8283
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SHA1SignatureDescription.cs" />
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Xml;
6+
7+
namespace System.Security.Cryptography.Xml
8+
{
9+
// This type masks out System.Xml.XmlSecureResolver by being in the local namespace.
10+
internal sealed class XmlSecureResolver : XmlResolver
11+
{
12+
internal XmlSecureResolver(XmlResolver resolver, string securityUrl)
13+
{
14+
}
15+
16+
// Simulate .NET Framework's CAS behavior by throwing SecurityException.
17+
// Unlike .NET Framework's implementation, the securityUrl ctor parameter has no effect.
18+
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) =>
19+
throw new SecurityException();
20+
}
21+
}

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

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414

1515
using System.Globalization;
1616
using System.IO;
17+
using System.Net;
1718
using System.Security.Cryptography.X509Certificates;
1819
using System.Text;
20+
using System.Threading;
21+
using System.Threading.Tasks;
1922
using System.Xml;
2023
using System.Xml.XPath;
2124
using Xunit;
@@ -1577,6 +1580,128 @@ public void VerifyHMAC_HMACOutputLength_Invalid()
15771580
Assert.Throws<FormatException>(() => sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("no clue"))));
15781581
}
15791582

1583+
[Theory]
1584+
[InlineData(false)]
1585+
[InlineData(true)]
1586+
public void VerifyXmlResolver(bool provideResolver)
1587+
{
1588+
HttpListener listener;
1589+
int port = 9000;
1590+
1591+
while (true)
1592+
{
1593+
listener = new HttpListener();
1594+
listener.Prefixes.Add($"http://127.0.0.1:{port}/");
1595+
listener.IgnoreWriteExceptions = true;
1596+
1597+
try
1598+
{
1599+
listener.Start();
1600+
break;
1601+
}
1602+
catch
1603+
{
1604+
}
1605+
1606+
port++;
1607+
1608+
if (port > 10000)
1609+
{
1610+
throw new InvalidOperationException("Could not find an open port");
1611+
}
1612+
}
1613+
1614+
string xml = $@"<!DOCTYPE foo [<!ENTITY xxe SYSTEM ""http://127.0.0.1:{port}/"" >]>
1615+
<ExampleDoc>Example doc to be signed.&xxe;<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#"">
1616+
<SignedInfo>
1617+
<CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" />
1618+
<SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"" />
1619+
<Reference URI="""">
1620+
<Transforms>
1621+
<Transform Algorithm=""http://www.w3.org/2000/09/xmldsig#enveloped-signature"" />
1622+
</Transforms>
1623+
<DigestMethod Algorithm=""http://www.w3.org/2001/04/xmlenc#sha256"" />
1624+
<DigestValue>CLUSJx4H4EwydAT/CtNWYu/l6R8uZe0tO2rlM/o0iM4=</DigestValue>
1625+
</Reference>
1626+
</SignedInfo>
1627+
<SignatureValue>o0IAVyovNUYKs5CCIRpZVy6noLpdJBp8LwWrqzzhKPg=</SignatureValue>
1628+
</Signature>
1629+
</ExampleDoc>";
1630+
1631+
bool listenerContacted = false;
1632+
CancellationTokenSource tokenSource = new CancellationTokenSource();
1633+
Task listenerTask = VerifyXmlResolver_ProcessRequests(listener, req => listenerContacted = true, tokenSource.Token);
1634+
1635+
XmlDocument doc = new XmlDocument();
1636+
doc.LoadXml(xml);
1637+
1638+
SignedXml signedXml = new SignedXml(doc);
1639+
signedXml.LoadXml((XmlElement)doc.GetElementsByTagName("Signature")[0]);
1640+
1641+
try
1642+
{
1643+
using (HMAC key = new HMACSHA256(Encoding.UTF8.GetBytes("sample")))
1644+
{
1645+
if (provideResolver)
1646+
{
1647+
signedXml.Resolver = new XmlUrlResolver();
1648+
Assert.True(signedXml.CheckSignature(key), "signedXml.CheckSignature(key)");
1649+
Assert.True(listenerContacted, "listenerContacted");
1650+
}
1651+
else
1652+
{
1653+
XmlException ex = Assert.Throws<XmlException>(() => signedXml.CheckSignature(key));
1654+
Assert.IsType<SecurityException>(ex.InnerException);
1655+
Assert.False(listenerContacted, "listenerContacted");
1656+
}
1657+
}
1658+
}
1659+
finally
1660+
{
1661+
tokenSource.Cancel();
1662+
1663+
try
1664+
{
1665+
listener.Stop();
1666+
}
1667+
catch
1668+
{
1669+
}
1670+
1671+
((IDisposable)listener).Dispose();
1672+
}
1673+
}
1674+
1675+
private static async Task VerifyXmlResolver_ProcessRequests(
1676+
HttpListener listener,
1677+
Action<HttpListenerRequest> requestReceived,
1678+
CancellationToken cancellationToken)
1679+
{
1680+
while (!cancellationToken.IsCancellationRequested)
1681+
{
1682+
HttpListenerContext ctx;
1683+
1684+
try
1685+
{
1686+
ctx = await listener.GetContextAsync();
1687+
}
1688+
catch
1689+
{
1690+
break;
1691+
}
1692+
1693+
HttpListenerRequest req = ctx.Request;
1694+
requestReceived(req);
1695+
1696+
using (HttpListenerResponse resp = ctx.Response)
1697+
{
1698+
resp.ContentType = "text/plain";
1699+
resp.ContentEncoding = Encoding.UTF8;
1700+
resp.ContentLength64 = 0;
1701+
}
1702+
}
1703+
}
1704+
15801705
[Fact]
15811706
public void CoreFxSignedXmlUsesSha256ByDefault()
15821707
{

src/packages.builds

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
<AdditionalProperties>$(AdditionalProperties)</AdditionalProperties>
2727
</Project>
2828
<!-- add specific builds / pkgproj's here to include in servicing builds -->
29+
<Project Include="$(MSBuildThisFileDirectory)System.Security.Cryptography.Xml\pkg\System.Security.Cryptography.Xml.pkgproj">
30+
<AdditionalProperties>$(AdditionalProperties)</AdditionalProperties>
31+
</Project>
2932
</ItemGroup>
3033

3134
<ItemGroup>

0 commit comments

Comments
 (0)