Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Forbid XML external entity resolution in crypto APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
GrabYourPitchforks committed Jul 12, 2022
1 parent a6ab07a commit 644880b
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 5 deletions.
7 changes: 4 additions & 3 deletions pkg/Microsoft.Private.PackageBaseline/packageIndex.json
Original file line number Diff line number Diff line change
Expand Up @@ -5108,13 +5108,14 @@
"4.6.0",
"4.7.0"
],
"BaselineVersion": "4.7.0",
"BaselineVersion": "4.7.1",
"InboxOn": {},
"AssemblyVersionInPackageVersion": {
"4.0.0.0": "4.4.0",
"4.0.1.0": "4.5.0",
"4.0.2.0": "4.6.0",
"4.0.3.0": "4.7.0"
"4.0.3.0": "4.7.0",
"4.0.3.1": "4.7.1"
}
},
"System.Security.Permissions": {
Expand Down Expand Up @@ -6661,4 +6662,4 @@
"System.Xml.XDocument"
]
}
}
}
3 changes: 2 additions & 1 deletion src/System.Security.Cryptography.Xml/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<Project>
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<AssemblyVersion>4.0.3.0</AssemblyVersion>
<AssemblyVersion>4.0.3.1</AssemblyVersion>
<PackageVersion>4.7.1</PackageVersion>
<StrongNameKeyId>Open</StrongNameKeyId>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>System.Security.Cryptography.Xml</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Expand Down Expand Up @@ -77,6 +77,7 @@
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXPathTransform.cs" />
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXsltTransform.cs" />
<Compile Include="System\Security\Cryptography\Xml\XmlLicenseTransform.cs" />
<Compile Include="System\Security\Cryptography\Xml\XmlSecureResolver.cs" />
<Compile Include="System\Security\Cryptography\Xml\CryptoHelpers.cs" />
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SignatureDescription.cs" />
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SHA1SignatureDescription.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Xml;

namespace System.Security.Cryptography.Xml
{
// This type masks out System.Xml.XmlSecureResolver by being in the local namespace.
internal sealed class XmlSecureResolver : XmlResolver
{
internal XmlSecureResolver(XmlResolver resolver, string securityUrl)
{
}

// Simulate .NET Framework's CAS behavior by throwing SecurityException.
// Unlike .NET Framework's implementation, the securityUrl ctor parameter has no effect.
public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) =>
throw new SecurityException();
}
}
125 changes: 125 additions & 0 deletions src/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@

using System.Globalization;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.XPath;
using Xunit;
Expand Down Expand Up @@ -1577,6 +1580,128 @@ public void VerifyHMAC_HMACOutputLength_Invalid()
Assert.Throws<FormatException>(() => sign.CheckSignature(new HMACSHA1(Encoding.ASCII.GetBytes("no clue"))));
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void VerifyXmlResolver(bool provideResolver)
{
HttpListener listener;
int port = 9000;

while (true)
{
listener = new HttpListener();
listener.Prefixes.Add($"http://127.0.0.1:{port}/");
listener.IgnoreWriteExceptions = true;

try
{
listener.Start();
break;
}
catch
{
}

port++;

if (port > 10000)
{
throw new InvalidOperationException("Could not find an open port");
}
}

string xml = $@"<!DOCTYPE foo [<!ENTITY xxe SYSTEM ""http://127.0.0.1:{port}/"" >]>
<ExampleDoc>Example doc to be signed.&xxe;<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#"">
<SignedInfo>
<CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" />
<SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"" />
<Reference URI="""">
<Transforms>
<Transform Algorithm=""http://www.w3.org/2000/09/xmldsig#enveloped-signature"" />
</Transforms>
<DigestMethod Algorithm=""http://www.w3.org/2001/04/xmlenc#sha256"" />
<DigestValue>CLUSJx4H4EwydAT/CtNWYu/l6R8uZe0tO2rlM/o0iM4=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>o0IAVyovNUYKs5CCIRpZVy6noLpdJBp8LwWrqzzhKPg=</SignatureValue>
</Signature>
</ExampleDoc>";

bool listenerContacted = false;
CancellationTokenSource tokenSource = new CancellationTokenSource();
Task listenerTask = VerifyXmlResolver_ProcessRequests(listener, req => listenerContacted = true, tokenSource.Token);

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);

SignedXml signedXml = new SignedXml(doc);
signedXml.LoadXml((XmlElement)doc.GetElementsByTagName("Signature")[0]);

try
{
using (HMAC key = new HMACSHA256(Encoding.UTF8.GetBytes("sample")))
{
if (provideResolver)
{
signedXml.Resolver = new XmlUrlResolver();
Assert.True(signedXml.CheckSignature(key), "signedXml.CheckSignature(key)");
Assert.True(listenerContacted, "listenerContacted");
}
else
{
XmlException ex = Assert.Throws<XmlException>(() => signedXml.CheckSignature(key));
Assert.IsType<SecurityException>(ex.InnerException);
Assert.False(listenerContacted, "listenerContacted");
}
}
}
finally
{
tokenSource.Cancel();

try
{
listener.Stop();
}
catch
{
}

((IDisposable)listener).Dispose();
}
}

private static async Task VerifyXmlResolver_ProcessRequests(
HttpListener listener,
Action<HttpListenerRequest> requestReceived,
CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
HttpListenerContext ctx;

try
{
ctx = await listener.GetContextAsync();
}
catch
{
break;
}

HttpListenerRequest req = ctx.Request;
requestReceived(req);

using (HttpListenerResponse resp = ctx.Response)
{
resp.ContentType = "text/plain";
resp.ContentEncoding = Encoding.UTF8;
resp.ContentLength64 = 0;
}
}
}

[Fact]
public void CoreFxSignedXmlUsesSha256ByDefault()
{
Expand Down
3 changes: 3 additions & 0 deletions src/packages.builds
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
<AdditionalProperties>$(AdditionalProperties)</AdditionalProperties>
</Project>
<!-- add specific builds / pkgproj's here to include in servicing builds -->
<Project Include="$(MSBuildThisFileDirectory)System.Security.Cryptography.Xml\pkg\System.Security.Cryptography.Xml.pkgproj">
<AdditionalProperties>$(AdditionalProperties)</AdditionalProperties>
</Project>
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 644880b

Please sign in to comment.