mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-10 01:50:53 +09:00
Obsolete XmlSecureResolver (#73676)
- Add XmlResolver.ThrowingResolver - Migrate all call sites to the new API - Improve error messages on failure Resolves CVE-2022-34716.
This commit is contained in:
parent
f44da5225f
commit
d2afae4fb0
36 changed files with 474 additions and 124 deletions
|
@ -101,6 +101,7 @@ The PR that reveals the implementation of the `<IncludeInternalObsoleteAttribute
|
||||||
| __`SYSLIB0044`__ | AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported. |
|
| __`SYSLIB0044`__ | AssemblyName.CodeBase and AssemblyName.EscapedCodeBase are obsolete. Using them for loading an assembly is not supported. |
|
||||||
| __`SYSLIB0045`__ | Cryptographic factory methods accepting an algorithm name are obsolete. Use the parameterless Create factory method on the algorithm type instead. |
|
| __`SYSLIB0045`__ | Cryptographic factory methods accepting an algorithm name are obsolete. Use the parameterless Create factory method on the algorithm type instead. |
|
||||||
| __`SYSLIB0046`__ | ControlledExecution.Run method may corrupt the process and should not be used in production code. |
|
| __`SYSLIB0046`__ | ControlledExecution.Run method may corrupt the process and should not be used in production code. |
|
||||||
|
| __`SYSLIB0047`__ | XmlSecureResolver is obsolete. Use XmlResolver.ThrowingResolver instead when attempting to forbid XML external entity resolution. |
|
||||||
|
|
||||||
## Analyzer Warnings
|
## Analyzer Warnings
|
||||||
|
|
||||||
|
|
|
@ -150,5 +150,8 @@ namespace System
|
||||||
|
|
||||||
internal const string ControlledExecutionRunMessage = "ControlledExecution.Run method may corrupt the process and should not be used in production code.";
|
internal const string ControlledExecutionRunMessage = "ControlledExecution.Run method may corrupt the process and should not be used in production code.";
|
||||||
internal const string ControlledExecutionRunDiagId = "SYSLIB0046";
|
internal const string ControlledExecutionRunDiagId = "SYSLIB0046";
|
||||||
|
|
||||||
|
internal const string XmlSecureResolverMessage = "XmlSecureResolver is obsolete. Use XmlResolver.ThrowingResolver instead when attempting to forbid XML external entity resolution.";
|
||||||
|
internal const string XmlSecureResolverDiagId = "SYSLIB0047";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@
|
||||||
<value>Object type is not supported.</value>
|
<value>Object type is not supported.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Xml_NullResolver" xml:space="preserve">
|
<data name="Xml_NullResolver" xml:space="preserve">
|
||||||
<value>Resolving of external URIs was prohibited.</value>
|
<value>Resolving of external URIs was prohibited. Attempted access to: {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Xml_RelativeUriNotSupported" xml:space="preserve">
|
<data name="Xml_RelativeUriNotSupported" xml:space="preserve">
|
||||||
<value>Relative URIs are not supported.</value>
|
<value>Relative URIs are not supported.</value>
|
||||||
|
|
|
@ -127,13 +127,11 @@
|
||||||
<Compile Include="System\Xml\XmlNameTable.cs" />
|
<Compile Include="System\Xml\XmlNameTable.cs" />
|
||||||
<Compile Include="System\Xml\XmlNodeOrder.cs" />
|
<Compile Include="System\Xml\XmlNodeOrder.cs" />
|
||||||
<Compile Include="System\Xml\XmlNodeType.cs" />
|
<Compile Include="System\Xml\XmlNodeType.cs" />
|
||||||
<Compile Include="System\Xml\XmlNullResolver.cs" />
|
|
||||||
<Compile Include="System\Xml\XmlQualifiedName.cs" />
|
<Compile Include="System\Xml\XmlQualifiedName.cs" />
|
||||||
<Compile Include="System\Xml\XmlReservedNs.cs" />
|
<Compile Include="System\Xml\XmlReservedNs.cs" />
|
||||||
<Compile Include="System\Xml\XmlResolver.cs" />
|
<Compile Include="System\Xml\XmlResolver.cs" />
|
||||||
<Compile Include="System\Xml\XmlResolverAsync.cs" />
|
<Compile Include="System\Xml\XmlResolver.ThrowingResolver.cs" />
|
||||||
<Compile Include="System\Xml\XmlSecureResolver.cs" />
|
<Compile Include="System\Xml\XmlSecureResolver.cs" />
|
||||||
<Compile Include="System\Xml\XmlSecureResolverAsync.cs" />
|
|
||||||
<Compile Include="System\Xml\XmlUrlResolver.cs" />
|
<Compile Include="System\Xml\XmlUrlResolver.cs" />
|
||||||
<Compile Include="System\Xml\XmlUrlResolverAsync.cs" />
|
<Compile Include="System\Xml\XmlUrlResolverAsync.cs" />
|
||||||
<Compile Include="System\Xml\Core\CharEntityEncoderFallback.cs" />
|
<Compile Include="System\Xml\Core\CharEntityEncoderFallback.cs" />
|
||||||
|
@ -748,6 +746,7 @@
|
||||||
<Compile Include="$(CommonPath)System\CSharpHelpers.cs" />
|
<Compile Include="$(CommonPath)System\CSharpHelpers.cs" />
|
||||||
<Compile Include="$(CommonPath)System\Text\ValueStringBuilder.cs" Link="Common\System\Text\ValueStringBuilder.cs" />
|
<Compile Include="$(CommonPath)System\Text\ValueStringBuilder.cs" Link="Common\System\Text\ValueStringBuilder.cs" />
|
||||||
<Compile Include="$(CommonPath)System\Text\ValueStringBuilder.AppendSpanFormattable.cs" Link="Common\System\Text\ValueStringBuilder.AppendSpanFormattable.cs" />
|
<Compile Include="$(CommonPath)System\Text\ValueStringBuilder.AppendSpanFormattable.cs" Link="Common\System\Text\ValueStringBuilder.AppendSpanFormattable.cs" />
|
||||||
|
<Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
|
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
|
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace System.Xml
|
|
||||||
{
|
|
||||||
internal sealed class XmlNullResolver : XmlResolver
|
|
||||||
{
|
|
||||||
public static readonly XmlNullResolver Singleton = new XmlNullResolver();
|
|
||||||
|
|
||||||
// Private constructor ensures existing only one instance of XmlNullResolver
|
|
||||||
private XmlNullResolver() { }
|
|
||||||
|
|
||||||
public override object GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
|
||||||
{
|
|
||||||
throw new XmlException(SR.Xml_NullResolver, string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ICredentials Credentials
|
|
||||||
{
|
|
||||||
set { /* Do nothing */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace System.Xml
|
||||||
|
{
|
||||||
|
public abstract partial class XmlResolver
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an XML resolver which forbids entity resolution.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>An XML resolver which forbids entity resolution.</value>
|
||||||
|
/// <remarks>
|
||||||
|
/// Calling <see cref="GetEntity"/> or <see cref="GetEntityAsync"/> on the
|
||||||
|
/// <see cref="XmlResolver"/> instance returned by this property is forbidden
|
||||||
|
/// and will result in <see cref="XmlException"/> being thrown.
|
||||||
|
///
|
||||||
|
/// Use <see cref="ThrowingResolver"/> when external entity resolution must be
|
||||||
|
/// prohibited, even when DTD processing is otherwise enabled.
|
||||||
|
/// </remarks>
|
||||||
|
public static XmlResolver ThrowingResolver => XmlThrowingResolver.s_singleton;
|
||||||
|
|
||||||
|
// An XmlResolver that forbids all external entity resolution.
|
||||||
|
private sealed class XmlThrowingResolver : XmlResolver
|
||||||
|
{
|
||||||
|
internal static readonly XmlThrowingResolver s_singleton = new();
|
||||||
|
|
||||||
|
// Private constructor ensures existing only one instance of XmlThrowingResolver
|
||||||
|
private XmlThrowingResolver() { }
|
||||||
|
|
||||||
|
public override ICredentials Credentials
|
||||||
|
{
|
||||||
|
set { /* Do nothing */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
throw new XmlException(SR.Format(SR.Xml_NullResolver, absoluteUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<object> GetEntityAsync(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
throw new XmlException(SR.Format(SR.Xml_NullResolver, absoluteUri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,12 @@ namespace System.Xml
|
||||||
string? role,
|
string? role,
|
||||||
Type? ofObjectToReturn);
|
Type? ofObjectToReturn);
|
||||||
|
|
||||||
|
public virtual Task<object> GetEntityAsync(Uri absoluteUri,
|
||||||
|
string? role,
|
||||||
|
Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
/// <devdoc>
|
/// <devdoc>
|
||||||
/// <para>[To be supplied.]</para>
|
/// <para>[To be supplied.]</para>
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace System.Xml
|
|
||||||
{
|
|
||||||
public abstract partial class XmlResolver
|
|
||||||
{
|
|
||||||
public virtual Task<object> GetEntityAsync(Uri absoluteUri,
|
|
||||||
string? role,
|
|
||||||
Type? ofObjectToReturn)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,32 +3,31 @@
|
||||||
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Runtime.Versioning;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace System.Xml
|
namespace System.Xml
|
||||||
{
|
{
|
||||||
public partial class XmlSecureResolver : XmlResolver
|
[Obsolete(Obsoletions.XmlSecureResolverMessage, DiagnosticId = Obsoletions.XmlSecureResolverDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
|
||||||
|
public class XmlSecureResolver : XmlResolver
|
||||||
{
|
{
|
||||||
private readonly XmlResolver _resolver;
|
|
||||||
|
|
||||||
public XmlSecureResolver(XmlResolver resolver, string? securityUrl)
|
public XmlSecureResolver(XmlResolver resolver, string? securityUrl)
|
||||||
{
|
{
|
||||||
_resolver = resolver;
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ICredentials Credentials
|
public override ICredentials Credentials
|
||||||
{
|
{
|
||||||
set { _resolver.Credentials = value; }
|
set { /* no-op */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object? GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
// Forward to ThrowingResolver to get its exception message
|
||||||
{
|
public override object? GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn) => XmlResolver.ThrowingResolver.GetEntity(absoluteUri, role, ofObjectToReturn);
|
||||||
return _resolver.GetEntity(absoluteUri, role, ofObjectToReturn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Uri ResolveUri(Uri? baseUri, string? relativeUri)
|
// Forward to ThrowingResolver to get its exception message
|
||||||
{
|
public override Task<object> GetEntityAsync(Uri absoluteUri, string? role, Type? ofObjectToReturn) => XmlResolver.ThrowingResolver.GetEntityAsync(absoluteUri, role, ofObjectToReturn);
|
||||||
return _resolver.ResolveUri(baseUri, relativeUri);
|
|
||||||
}
|
// An earlier implementation of this type overrode this method, so we'll continue to do so
|
||||||
|
// to preserve binary compatibility.
|
||||||
|
public override Uri ResolveUri(Uri? baseUri, string? relativeUri) => base.ResolveUri(baseUri, relativeUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace System.Xml
|
|
||||||
{
|
|
||||||
public partial class XmlSecureResolver : XmlResolver
|
|
||||||
{
|
|
||||||
public override Task<object> GetEntityAsync(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
|
||||||
{
|
|
||||||
return _resolver.GetEntityAsync(absoluteUri, role, ofObjectToReturn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -83,7 +83,7 @@ namespace System.Xml.Xsl
|
||||||
Debug.Assert(results != null);
|
Debug.Assert(results != null);
|
||||||
|
|
||||||
// Ensure that dataSources is always non-null
|
// Ensure that dataSources is always non-null
|
||||||
dataSources ??= XmlNullResolver.Singleton;
|
dataSources ??= XmlResolver.ThrowingResolver;
|
||||||
|
|
||||||
_delExec(new XmlQueryRuntime(_staticData, defaultDocument, dataSources, argumentList, results));
|
_delExec(new XmlQueryRuntime(_staticData, defaultDocument, dataSources, argumentList, results));
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,12 +70,12 @@ namespace System.Xml.Xsl.Xslt
|
||||||
Scripts = new Scripts(this);
|
Scripts = new Scripts(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompilerErrorCollection Compile(object stylesheet, XmlResolver? xmlResolver, out QilExpression qil)
|
public CompilerErrorCollection Compile(object stylesheet, XmlResolver? xmlResolver, XmlResolver? origResolver, out QilExpression qil)
|
||||||
{
|
{
|
||||||
Debug.Assert(stylesheet != null);
|
Debug.Assert(stylesheet != null);
|
||||||
Debug.Assert(Root == null, "Compiler cannot be reused");
|
Debug.Assert(Root == null, "Compiler cannot be reused");
|
||||||
|
|
||||||
new XsltLoader().Load(this, stylesheet, xmlResolver);
|
new XsltLoader().Load(this, stylesheet, xmlResolver, origResolver);
|
||||||
qil = QilGenerator.CompileStylesheet(this);
|
qil = QilGenerator.CompileStylesheet(this);
|
||||||
SortErrors();
|
SortErrors();
|
||||||
return CompilerErrorColl;
|
return CompilerErrorColl;
|
||||||
|
|
|
@ -38,11 +38,11 @@ namespace System.Xml.Xsl.Xslt
|
||||||
public static int V2Opt = 4;
|
public static int V2Opt = 4;
|
||||||
public static int V2Req = 8;
|
public static int V2Req = 8;
|
||||||
|
|
||||||
public void Load(Compiler compiler, object stylesheet, XmlResolver? xmlResolver)
|
public void Load(Compiler compiler, object stylesheet, XmlResolver? xmlResolver, XmlResolver? origResolver)
|
||||||
{
|
{
|
||||||
Debug.Assert(compiler != null);
|
Debug.Assert(compiler != null);
|
||||||
_compiler = compiler;
|
_compiler = compiler;
|
||||||
_xmlResolver = xmlResolver ?? XmlNullResolver.Singleton;
|
_xmlResolver = xmlResolver ?? XmlResolver.ThrowingResolver;
|
||||||
|
|
||||||
XmlReader? reader = stylesheet as XmlReader;
|
XmlReader? reader = stylesheet as XmlReader;
|
||||||
if (reader != null)
|
if (reader != null)
|
||||||
|
@ -57,10 +57,21 @@ namespace System.Xml.Xsl.Xslt
|
||||||
string? uri = stylesheet as string;
|
string? uri = stylesheet as string;
|
||||||
if (uri != null)
|
if (uri != null)
|
||||||
{
|
{
|
||||||
// If xmlResolver == null, then the original uri will be resolved using XmlUrlResolver
|
// If the stylesheet has been provided as a string (URI, really), then we'll bounce
|
||||||
XmlResolver origResolver = xmlResolver!;
|
// through an XmlResolver to look up its contents. There's a complication here since
|
||||||
if (xmlResolver == null || xmlResolver == XmlNullResolver.Singleton)
|
// the default resolver provided by our caller is likely a throwing resolver, and
|
||||||
origResolver = new XmlUrlResolver();
|
// a throwing resolver would fail even when attempting to read this URL. We need
|
||||||
|
// to at minimum allow this URL to be read, because the user after all did explicitly
|
||||||
|
// ask us to do so.
|
||||||
|
//
|
||||||
|
// In this case, we'll rely on the 'origResolver' argument, which is the XmlResolver
|
||||||
|
// which was provided *to our caller* before any default substitution took place.
|
||||||
|
// If an explicit resolver was specified, we'll honor it. Otherwise we'll substitute
|
||||||
|
// an XmlUrlResolver for this one read operation. The stored resolver (which is used
|
||||||
|
// for reads beyond the initial stylesheet read) will use a throwing resolver as its
|
||||||
|
// default, as shown at the very top of this method.
|
||||||
|
|
||||||
|
origResolver ??= new XmlUrlResolver();
|
||||||
Uri resolvedUri = origResolver.ResolveUri(null, uri);
|
Uri resolvedUri = origResolver.ResolveUri(null, uri);
|
||||||
if (resolvedUri == null)
|
if (resolvedUri == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -345,7 +345,7 @@ namespace System.Xml.Xsl.XsltOld
|
||||||
_builder = null;
|
_builder = null;
|
||||||
_actionStack = new HWStack(StackIncrement);
|
_actionStack = new HWStack(StackIncrement);
|
||||||
_output = _rootAction.Output;
|
_output = _rootAction.Output;
|
||||||
_resolver = resolver ?? XmlNullResolver.Singleton;
|
_resolver = resolver ?? XmlResolver.ThrowingResolver;
|
||||||
_args = args ?? new XsltArgumentList();
|
_args = args ?? new XsltArgumentList();
|
||||||
_debugger = debugger;
|
_debugger = debugger;
|
||||||
if (_debugger != null)
|
if (_debugger != null)
|
||||||
|
|
|
@ -82,7 +82,7 @@ namespace System.Xml.Xsl
|
||||||
public void Load(XmlReader stylesheet)
|
public void Load(XmlReader stylesheet)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
LoadInternal(stylesheet, XsltSettings.Default, CreateDefaultResolver());
|
LoadInternal(stylesheet, XsltSettings.Default, CreateDefaultResolver(), originalStylesheetResolver: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SxS: This method does not take any resource name and does not expose any resources to the caller.
|
// SxS: This method does not take any resource name and does not expose any resources to the caller.
|
||||||
|
@ -90,7 +90,7 @@ namespace System.Xml.Xsl
|
||||||
public void Load(XmlReader stylesheet, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
public void Load(XmlReader stylesheet, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
LoadInternal(stylesheet, settings, stylesheetResolver);
|
LoadInternal(stylesheet, settings, stylesheetResolver, stylesheetResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SxS: This method does not take any resource name and does not expose any resources to the caller.
|
// SxS: This method does not take any resource name and does not expose any resources to the caller.
|
||||||
|
@ -98,7 +98,7 @@ namespace System.Xml.Xsl
|
||||||
public void Load(IXPathNavigable stylesheet)
|
public void Load(IXPathNavigable stylesheet)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
LoadInternal(stylesheet, XsltSettings.Default, CreateDefaultResolver());
|
LoadInternal(stylesheet, XsltSettings.Default, CreateDefaultResolver(), originalStylesheetResolver: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SxS: This method does not take any resource name and does not expose any resources to the caller.
|
// SxS: This method does not take any resource name and does not expose any resources to the caller.
|
||||||
|
@ -106,29 +106,32 @@ namespace System.Xml.Xsl
|
||||||
public void Load(IXPathNavigable stylesheet, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
public void Load(IXPathNavigable stylesheet, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
LoadInternal(stylesheet, settings, stylesheetResolver);
|
LoadInternal(stylesheet, settings, stylesheetResolver, stylesheetResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(string stylesheetUri)
|
public void Load(string stylesheetUri)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
ArgumentNullException.ThrowIfNull(stylesheetUri);
|
ArgumentNullException.ThrowIfNull(stylesheetUri);
|
||||||
LoadInternal(stylesheetUri, XsltSettings.Default, CreateDefaultResolver());
|
LoadInternal(stylesheetUri, XsltSettings.Default, CreateDefaultResolver(), originalStylesheetResolver: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(string stylesheetUri, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
public void Load(string stylesheetUri, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
ArgumentNullException.ThrowIfNull(stylesheetUri);
|
ArgumentNullException.ThrowIfNull(stylesheetUri);
|
||||||
LoadInternal(stylesheetUri, settings, stylesheetResolver);
|
LoadInternal(stylesheetUri, settings, stylesheetResolver, stylesheetResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadInternal(object stylesheet, XsltSettings? settings, XmlResolver? stylesheetResolver)
|
// The 'originalStylesheetResolver' argument should be the original XmlResolver
|
||||||
|
// that was passed to the caller (or null), *before* any default substitutions
|
||||||
|
// were made by the caller.
|
||||||
|
private void LoadInternal(object stylesheet, XsltSettings? settings, XmlResolver? stylesheetResolver, XmlResolver? originalStylesheetResolver)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(stylesheet);
|
ArgumentNullException.ThrowIfNull(stylesheet);
|
||||||
|
|
||||||
settings ??= XsltSettings.Default;
|
settings ??= XsltSettings.Default;
|
||||||
CompileXsltToQil(stylesheet, settings, stylesheetResolver);
|
CompileXsltToQil(stylesheet, settings, stylesheetResolver, originalStylesheetResolver);
|
||||||
CompilerError? error = GetFirstError();
|
CompilerError? error = GetFirstError();
|
||||||
if (error != null)
|
if (error != null)
|
||||||
{
|
{
|
||||||
|
@ -142,9 +145,9 @@ namespace System.Xml.Xsl
|
||||||
|
|
||||||
[MemberNotNull(nameof(_compilerErrorColl))]
|
[MemberNotNull(nameof(_compilerErrorColl))]
|
||||||
[MemberNotNull(nameof(_qil))]
|
[MemberNotNull(nameof(_qil))]
|
||||||
private void CompileXsltToQil(object stylesheet, XsltSettings settings, XmlResolver? stylesheetResolver)
|
private void CompileXsltToQil(object stylesheet, XsltSettings settings, XmlResolver? stylesheetResolver, XmlResolver? originalStylesheetResolver)
|
||||||
{
|
{
|
||||||
_compilerErrorColl = new Compiler(settings, _enableDebug, null).Compile(stylesheet, stylesheetResolver, out _qil);
|
_compilerErrorColl = new Compiler(settings, _enableDebug, null).Compile(stylesheet, stylesheetResolver, originalStylesheetResolver, out _qil);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -405,7 +408,7 @@ namespace System.Xml.Xsl
|
||||||
return new XmlUrlResolver();
|
return new XmlUrlResolver();
|
||||||
}
|
}
|
||||||
|
|
||||||
return XmlNullResolver.Singleton;
|
return XmlResolver.ThrowingResolver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ namespace System.Xml.Xsl
|
||||||
|
|
||||||
Compiler compiler = new Compiler();
|
Compiler compiler = new Compiler();
|
||||||
NavigatorInput input = new NavigatorInput(stylesheet);
|
NavigatorInput input = new NavigatorInput(stylesheet);
|
||||||
compiler.Compile(input, resolver ?? XmlNullResolver.Singleton);
|
compiler.Compile(input, resolver ?? XmlResolver.ThrowingResolver);
|
||||||
|
|
||||||
Debug.Assert(compiler.CompiledStylesheet != null);
|
Debug.Assert(compiler.CompiledStylesheet != null);
|
||||||
Debug.Assert(compiler.QueryStore != null);
|
Debug.Assert(compiler.QueryStore != null);
|
||||||
|
@ -264,7 +264,7 @@ namespace System.Xml.Xsl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return XmlNullResolver.Singleton;
|
return XmlResolver.ThrowingResolver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
|
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="XmlThrowingResolverTests.cs" />
|
||||||
|
<Compile Include="XmlSecureResolverTests.cs" />
|
||||||
<Compile Include="XmlUrlResolverTests.cs" />
|
<Compile Include="XmlUrlResolverTests.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
#pragma warning disable SYSLIB0047 // XmlSecureResolver is obsolete
|
||||||
|
|
||||||
|
namespace System.Xml.Tests
|
||||||
|
{
|
||||||
|
public class XmlSecureResolverTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetEntity_ThrowsXmlException()
|
||||||
|
{
|
||||||
|
PoisonedXmlResolver innerResolver = new PoisonedXmlResolver();
|
||||||
|
XmlSecureResolver outerResolver = new XmlSecureResolver(innerResolver, "some-url");
|
||||||
|
Uri absoluteUri = new Uri("https://dot.net/");
|
||||||
|
Type typeToReturn = typeof(Stream);
|
||||||
|
|
||||||
|
Assert.Throws<XmlException>(() => outerResolver.GetEntity(absoluteUri, "role", typeToReturn));
|
||||||
|
Assert.False(innerResolver.WasAnyApiInvoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetEntityAsync_ThrowsXmlException()
|
||||||
|
{
|
||||||
|
PoisonedXmlResolver innerResolver = new PoisonedXmlResolver();
|
||||||
|
XmlSecureResolver outerResolver = new XmlSecureResolver(innerResolver, "some-url");
|
||||||
|
Uri absoluteUri = new Uri("https://dot.net/");
|
||||||
|
Type typeToReturn = typeof(Stream);
|
||||||
|
|
||||||
|
Assert.Throws<XmlException>(() => (object)outerResolver.GetEntityAsync(absoluteUri, "role", typeToReturn));
|
||||||
|
Assert.False(innerResolver.WasAnyApiInvoked);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Instance_HasNoState()
|
||||||
|
{
|
||||||
|
// This is a safety check to ensure we're not keeping the inner resolver in an instance field,
|
||||||
|
// since we don't want to risk invoking it.
|
||||||
|
|
||||||
|
FieldInfo[] allDeclaredInstanceFields = typeof(XmlSecureResolver).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
Assert.Empty(allDeclaredInstanceFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class PoisonedXmlResolver : XmlResolver
|
||||||
|
{
|
||||||
|
public bool WasAnyApiInvoked { get; private set; }
|
||||||
|
|
||||||
|
public override ICredentials Credentials
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
WasAnyApiInvoked = true;
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object? GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
WasAnyApiInvoked = true;
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<object> GetEntityAsync(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
WasAnyApiInvoked = true;
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Uri ResolveUri(Uri? baseUri, string? relativeUri)
|
||||||
|
{
|
||||||
|
WasAnyApiInvoked = true;
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool SupportsType(Uri absoluteUri, Type? type)
|
||||||
|
{
|
||||||
|
WasAnyApiInvoked = true;
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace System.Xml.Tests
|
||||||
|
{
|
||||||
|
public class XmlThrowingResolverTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void PropertyAccessor_ReturnsSingleton()
|
||||||
|
{
|
||||||
|
XmlResolver resolver1 = XmlResolver.ThrowingResolver;
|
||||||
|
Assert.NotNull(resolver1);
|
||||||
|
|
||||||
|
XmlResolver resolver2 = XmlResolver.ThrowingResolver;
|
||||||
|
Assert.Same(resolver1, resolver2);
|
||||||
|
Assert.Equal(resolver1, resolver2); // default comparer should also say they're equal
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetEntity_ThrowsXmlException()
|
||||||
|
{
|
||||||
|
XmlResolver resolver = XmlResolver.ThrowingResolver;
|
||||||
|
Uri absoluteUri = new Uri("https://dot.net/");
|
||||||
|
Type typeToReturn = typeof(Stream);
|
||||||
|
|
||||||
|
Assert.Throws<XmlException>(() => resolver.GetEntity(absoluteUri, "role", typeToReturn));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetEntityAsync_ThrowsXmlException()
|
||||||
|
{
|
||||||
|
XmlResolver resolver = XmlResolver.ThrowingResolver;
|
||||||
|
Uri absoluteUri = new Uri("https://dot.net/");
|
||||||
|
Type typeToReturn = typeof(Stream);
|
||||||
|
|
||||||
|
Assert.Throws<XmlException>(() => (object)resolver.GetEntityAsync(absoluteUri, "role", typeToReturn));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,12 +86,6 @@ namespace System.Xml.Tests
|
||||||
_resolver = new XmlUrlResolver();
|
_resolver = new XmlUrlResolver();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CXmlTestResolver(string securityUri)
|
|
||||||
: base()
|
|
||||||
{
|
|
||||||
_resolver = new XmlSecureResolver(new XmlUrlResolver(), securityUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------
|
// -----------------
|
||||||
// Events
|
// Events
|
||||||
// -----------------
|
// -----------------
|
||||||
|
|
|
@ -98,6 +98,6 @@
|
||||||
<!-- XML Exceptions -->
|
<!-- XML Exceptions -->
|
||||||
<exception res="Xml_BadStartNameChar" message="The '{0}' character, hexadecimal value {1}, cannot begin a name."/>
|
<exception res="Xml_BadStartNameChar" message="The '{0}' character, hexadecimal value {1}, cannot begin a name."/>
|
||||||
<exception res="Xml_ResolveUrl" message="There was an error accessing {0}."/>
|
<exception res="Xml_ResolveUrl" message="There was an error accessing {0}."/>
|
||||||
<exception res="Xml_NullResolver" message="Resolving of external URIs was prohibited. "/>
|
<exception res="Xml_NullResolver" message="Resolving of external URIs was prohibited. Attempted access to: {0}"/>
|
||||||
|
|
||||||
</exceptions>
|
</exceptions>
|
|
@ -101,6 +101,6 @@
|
||||||
<!-- XML Exceptions -->
|
<!-- XML Exceptions -->
|
||||||
<exception res="Xml_BadStartNameChar" message="The '{0}' character, hexadecimal value {1}, cannot begin a name."/>
|
<exception res="Xml_BadStartNameChar" message="The '{0}' character, hexadecimal value {1}, cannot begin a name."/>
|
||||||
<exception res="Xml_ResolveUrl" message="There was an error accessing {0}."/>
|
<exception res="Xml_ResolveUrl" message="There was an error accessing {0}."/>
|
||||||
<exception res="Xml_NullResolver" message="Resolving of external URIs was prohibited. "/>
|
<exception res="Xml_NullResolver" message="Resolving of external URIs was prohibited. Attempted access to: {0}"/>
|
||||||
|
|
||||||
</exceptions>
|
</exceptions>
|
|
@ -5,6 +5,7 @@ using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
@ -1486,6 +1487,35 @@ namespace System.Xml.Tests
|
||||||
_output.WriteLine("Passing null stylesheet parameter should have thrown ArgumentNullException");
|
_output.WriteLine("Passing null stylesheet parameter should have thrown ArgumentNullException");
|
||||||
Assert.True(false);
|
Assert.True(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//[Variation("Call Load with custom resolver; custom resolver should be honored.")]
|
||||||
|
[InlineData(XslInputType.URI, ReaderType.XmlValidatingReader)]
|
||||||
|
[Theory]
|
||||||
|
public void LoadUrlResolver4(XslInputType xslInputType, ReaderType readerType)
|
||||||
|
{
|
||||||
|
var auditingResolver = new XmlAuditingUrlResolver();
|
||||||
|
LoadXSL_Resolver(Path.Combine("XmlResolver", "XmlResolverTestMain.xsl"), xslInputType, readerType, auditingResolver);
|
||||||
|
|
||||||
|
HashSet<Uri> expected = new()
|
||||||
|
{
|
||||||
|
new Uri(Path.Combine(Environment.CurrentDirectory, FullFilePath(Path.Combine("XmlResolver", "XmlResolverTestMain.xsl")))),
|
||||||
|
new Uri(Path.Combine(Environment.CurrentDirectory, FullFilePath(Path.Combine("XmlResolver", "XmlResolverInclude.xsl")))),
|
||||||
|
new Uri(Path.Combine(Environment.CurrentDirectory, FullFilePath(Path.Combine("XmlResolver", "XmlResolverImport.xsl")))),
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.Equal(expected, auditingResolver.FetchedUris);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class XmlAuditingUrlResolver : XmlUrlResolver
|
||||||
|
{
|
||||||
|
internal readonly HashSet<Uri> FetchedUris = new();
|
||||||
|
|
||||||
|
public override object? GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
FetchedUris.Add(absoluteUri);
|
||||||
|
return base.GetEntity(absoluteUri, role, ofObjectToReturn);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
|
|
|
@ -1019,7 +1019,8 @@ namespace System.Xml.Tests
|
||||||
}
|
}
|
||||||
catch (System.Xml.Xsl.XsltCompileException e)
|
catch (System.Xml.Xsl.XsltCompileException e)
|
||||||
{
|
{
|
||||||
CheckExpectedError(e.InnerException, "System.Xml", "Xml_NullResolver", new string[] { "" });
|
var absoluteUri = new Uri(Path.Combine(Environment.CurrentDirectory, FullFilePath("XmlResolver_Include.xsl"))).AbsoluteUri;
|
||||||
|
CheckExpectedError(e.InnerException, "System.Xml", "Xml_NullResolver", new string[] { absoluteUri });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_output.WriteLine("Exception not thrown for null resolver");
|
_output.WriteLine("Exception not thrown for null resolver");
|
||||||
|
@ -1104,7 +1105,9 @@ namespace System.Xml.Tests
|
||||||
Assert.False(isEnabled);
|
Assert.False(isEnabled);
|
||||||
var e = Assert.Throws<XsltCompileException>(() => LoadXSL("XmlResolver_Main.xsl", inputType, readerType));
|
var e = Assert.Throws<XsltCompileException>(() => LoadXSL("XmlResolver_Main.xsl", inputType, readerType));
|
||||||
var xmlException = Assert.IsType<XmlException>(e.InnerException);
|
var xmlException = Assert.IsType<XmlException>(e.InnerException);
|
||||||
CheckExpectedError(xmlException, "System.Xml", "Xml_NullResolver", Array.Empty<string>());
|
|
||||||
|
var absoluteUri = new Uri(Path.Combine(Environment.CurrentDirectory, FullFilePath("XmlResolver_Include.xsl"))).AbsoluteUri;
|
||||||
|
CheckExpectedError(xmlException, "System.Xml", "Xml_NullResolver", new string[] { absoluteUri });
|
||||||
}
|
}
|
||||||
|
|
||||||
//[Variation("Load with resolver with credentials, then load XSL that does not need cred.")]
|
//[Variation("Load with resolver with credentials, then load XSL that does not need cred.")]
|
||||||
|
|
|
@ -393,4 +393,7 @@
|
||||||
<data name="WrongRootElement" xml:space="preserve">
|
<data name="WrongRootElement" xml:space="preserve">
|
||||||
<value>Root element must be {0} element in namespace {1}</value>
|
<value>Root element must be {0} element in namespace {1}</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Cryptography_Xml_EntityResolutionNotSupported" xml:space="preserve">
|
||||||
|
<value>External entity resolution is not supported.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
|
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
@ -126,6 +126,7 @@ System.Security.Cryptography.Xml.XmlLicenseTransform</PackageDescription>
|
||||||
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXPathTransform.cs" />
|
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXPathTransform.cs" />
|
||||||
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXsltTransform.cs" />
|
<Compile Include="System\Security\Cryptography\Xml\XmlDsigXsltTransform.cs" />
|
||||||
<Compile Include="System\Security\Cryptography\Xml\XmlLicenseTransform.cs" />
|
<Compile Include="System\Security\Cryptography\Xml\XmlLicenseTransform.cs" />
|
||||||
|
<Compile Include="System\Security\Cryptography\Xml\XmlResolverHelper.cs" />
|
||||||
<Compile Include="System\Security\Cryptography\Xml\CryptoHelpers.cs" />
|
<Compile Include="System\Security\Cryptography\Xml\CryptoHelpers.cs" />
|
||||||
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SignatureDescription.cs" />
|
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SignatureDescription.cs" />
|
||||||
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SHA1SignatureDescription.cs" />
|
<Compile Include="System\Security\Cryptography\Xml\RSAPKCS1SHA1SignatureDescription.cs" />
|
||||||
|
|
|
@ -359,7 +359,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
{
|
{
|
||||||
case ReferenceTargetType.Stream:
|
case ReferenceTargetType.Stream:
|
||||||
// This is the easiest case. We already have a stream, so just pump it through the TransformChain
|
// This is the easiest case. We already have a stream, so just pump it through the TransformChain
|
||||||
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
hashInputStream = TransformChain.TransformToOctetStream((Stream)_refTarget, resolver, baseUri);
|
hashInputStream = TransformChain.TransformToOctetStream((Stream)_refTarget, resolver, baseUri);
|
||||||
break;
|
break;
|
||||||
case ReferenceTargetType.UriReference:
|
case ReferenceTargetType.UriReference:
|
||||||
|
@ -369,7 +369,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
if (_uri == null)
|
if (_uri == null)
|
||||||
{
|
{
|
||||||
// We need to create a DocumentNavigator out of the XmlElement
|
// We need to create a DocumentNavigator out of the XmlElement
|
||||||
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
// In the case of a Uri-less reference, we will simply pass null to the transform chain.
|
// In the case of a Uri-less reference, we will simply pass null to the transform chain.
|
||||||
// The first transform in the chain is expected to know how to retrieve the data to hash.
|
// The first transform in the chain is expected to know how to retrieve the data to hash.
|
||||||
hashInputStream = TransformChain.TransformToOctetStream((Stream)null, resolver, baseUri);
|
hashInputStream = TransformChain.TransformToOctetStream((Stream)null, resolver, baseUri);
|
||||||
|
@ -382,7 +382,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
throw new CryptographicException(SR.Format(SR.Cryptography_Xml_SelfReferenceRequiresContext, _uri));
|
throw new CryptographicException(SR.Format(SR.Cryptography_Xml_SelfReferenceRequiresContext, _uri));
|
||||||
|
|
||||||
// Normalize the containing document
|
// Normalize the containing document
|
||||||
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
XmlDocument docWithNoComments = Utils.DiscardComments(Utils.PreProcessDocumentInput(document, resolver, baseUri));
|
XmlDocument docWithNoComments = Utils.DiscardComments(Utils.PreProcessDocumentInput(document, resolver, baseUri));
|
||||||
hashInputStream = TransformChain.TransformToOctetStream(docWithNoComments, resolver, baseUri);
|
hashInputStream = TransformChain.TransformToOctetStream(docWithNoComments, resolver, baseUri);
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
throw new CryptographicException(SR.Format(SR.Cryptography_Xml_SelfReferenceRequiresContext, _uri));
|
throw new CryptographicException(SR.Format(SR.Cryptography_Xml_SelfReferenceRequiresContext, _uri));
|
||||||
|
|
||||||
// We should not discard comments here!!!
|
// We should not discard comments here!!!
|
||||||
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
hashInputStream = TransformChain.TransformToOctetStream(Utils.PreProcessDocumentInput(document, resolver, baseUri), resolver, baseUri);
|
hashInputStream = TransformChain.TransformToOctetStream(Utils.PreProcessDocumentInput(document, resolver, baseUri), resolver, baseUri);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -434,7 +434,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
// Add the propagated attributes
|
// Add the propagated attributes
|
||||||
Utils.AddNamespaces(normDocument.DocumentElement, _namespaces);
|
Utils.AddNamespaces(normDocument.DocumentElement, _namespaces);
|
||||||
|
|
||||||
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
if (discardComments)
|
if (discardComments)
|
||||||
{
|
{
|
||||||
// We should discard comments before going into the transform chain
|
// We should discard comments before going into the transform chain
|
||||||
|
@ -454,7 +454,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
break;
|
break;
|
||||||
case ReferenceTargetType.XmlElement:
|
case ReferenceTargetType.XmlElement:
|
||||||
// We need to create a DocumentNavigator out of the XmlElement
|
// We need to create a DocumentNavigator out of the XmlElement
|
||||||
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
resolver = (SignedXml.ResolverSet ? SignedXml._xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
hashInputStream = TransformChain.TransformToOctetStream(Utils.PreProcessElementInput((XmlElement)_refTarget, resolver, baseUri), resolver, baseUri);
|
hashInputStream = TransformChain.TransformToOctetStream(Utils.PreProcessElementInput((XmlElement)_refTarget, resolver, baseUri), resolver, baseUri);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -775,7 +775,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
if (isKeyedHashAlgorithm || !_bCacheValid || !SignedInfo.CacheValid)
|
if (isKeyedHashAlgorithm || !_bCacheValid || !SignedInfo.CacheValid)
|
||||||
{
|
{
|
||||||
string baseUri = _containingDocument?.BaseURI;
|
string baseUri = _containingDocument?.BaseURI;
|
||||||
XmlResolver resolver = (_bResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), baseUri));
|
XmlResolver resolver = (_bResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
XmlDocument doc = Utils.PreProcessElementInput(SignedInfo.GetXml(), resolver, baseUri);
|
XmlDocument doc = Utils.PreProcessElementInput(SignedInfo.GetXml(), resolver, baseUri);
|
||||||
|
|
||||||
// Add non default namespaces in scope
|
// Add non default namespaces in scope
|
||||||
|
|
|
@ -142,7 +142,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
{
|
{
|
||||||
XmlDocument document = new XmlDocument();
|
XmlDocument document = new XmlDocument();
|
||||||
document.PreserveWhitespace = true;
|
document.PreserveWhitespace = true;
|
||||||
XmlResolver resolver = (ResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), BaseURI));
|
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
XmlReader xmlReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
|
XmlReader xmlReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
|
||||||
document.Load(xmlReader);
|
document.Load(xmlReader);
|
||||||
_containingDocument = document;
|
_containingDocument = document;
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
|
|
||||||
public override void LoadInput(object obj)
|
public override void LoadInput(object obj)
|
||||||
{
|
{
|
||||||
XmlResolver resolver = (ResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), BaseURI));
|
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
if (obj is Stream)
|
if (obj is Stream)
|
||||||
{
|
{
|
||||||
_cXml = new CanonicalXml((Stream)obj, _includeComments, resolver, BaseURI);
|
_cXml = new CanonicalXml((Stream)obj, _includeComments, resolver, BaseURI);
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
{
|
{
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = new XmlDocument();
|
||||||
doc.PreserveWhitespace = true;
|
doc.PreserveWhitespace = true;
|
||||||
XmlResolver resolver = (ResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), BaseURI));
|
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
XmlReader xmlReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
|
XmlReader xmlReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
|
||||||
doc.Load(xmlReader);
|
doc.Load(xmlReader);
|
||||||
_containingDocument = doc;
|
_containingDocument = doc;
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
|
|
||||||
public override void LoadInput(object obj)
|
public override void LoadInput(object obj)
|
||||||
{
|
{
|
||||||
XmlResolver resolver = (ResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), BaseURI));
|
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
if (obj is Stream)
|
if (obj is Stream)
|
||||||
{
|
{
|
||||||
_excCanonicalXml = new ExcCanonicalXml((Stream)obj, _includeComments, _inclusiveNamespacesPrefixList, resolver, BaseURI);
|
_excCanonicalXml = new ExcCanonicalXml((Stream)obj, _includeComments, _inclusiveNamespacesPrefixList, resolver, BaseURI);
|
||||||
|
|
|
@ -133,7 +133,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
|
|
||||||
private void LoadStreamInput(Stream stream)
|
private void LoadStreamInput(Stream stream)
|
||||||
{
|
{
|
||||||
XmlResolver resolver = (ResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), BaseURI));
|
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
XmlReader valReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
|
XmlReader valReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI);
|
||||||
_document = new XmlDocument();
|
_document = new XmlDocument();
|
||||||
_document.PreserveWhitespace = true;
|
_document.PreserveWhitespace = true;
|
||||||
|
@ -143,7 +143,7 @@ namespace System.Security.Cryptography.Xml
|
||||||
private void LoadXmlNodeListInput(XmlNodeList nodeList)
|
private void LoadXmlNodeListInput(XmlNodeList nodeList)
|
||||||
{
|
{
|
||||||
// Use C14N to get a document
|
// Use C14N to get a document
|
||||||
XmlResolver resolver = (ResolverSet ? _xmlResolver : new XmlSecureResolver(new XmlUrlResolver(), BaseURI));
|
XmlResolver resolver = (ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver());
|
||||||
CanonicalXml c14n = new CanonicalXml((XmlNodeList)nodeList, resolver, true);
|
CanonicalXml c14n = new CanonicalXml((XmlNodeList)nodeList, resolver, true);
|
||||||
using (MemoryStream ms = new MemoryStream(c14n.GetBytes()))
|
using (MemoryStream ms = new MemoryStream(c14n.GetBytes()))
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace System.Security.Cryptography.Xml
|
||||||
|
{
|
||||||
|
internal static class XmlResolverHelper
|
||||||
|
{
|
||||||
|
internal static XmlResolver GetThrowingResolver()
|
||||||
|
{
|
||||||
|
#if NET7_0_OR_GREATER
|
||||||
|
return XmlResolver.ThrowingResolver;
|
||||||
|
#else
|
||||||
|
return XmlThrowingResolver.s_singleton;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NET7_0_OR_GREATER
|
||||||
|
// An XmlResolver that forbids all external entity resolution.
|
||||||
|
// (Copied from XmlResolver.ThrowingResolver.cs.)
|
||||||
|
private sealed class XmlThrowingResolver : XmlResolver
|
||||||
|
{
|
||||||
|
internal static readonly XmlThrowingResolver s_singleton = new();
|
||||||
|
|
||||||
|
// Private constructor ensures existing only one instance of XmlThrowingResolver
|
||||||
|
private XmlThrowingResolver() { }
|
||||||
|
|
||||||
|
public override ICredentials Credentials
|
||||||
|
{
|
||||||
|
set { /* Do nothing */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
throw new XmlException(SR.Cryptography_Xml_EntityResolutionNotSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<object> GetEntityAsync(Uri absoluteUri, string? role, Type? ofObjectToReturn)
|
||||||
|
{
|
||||||
|
throw new XmlException(SR.Cryptography_Xml_EntityResolutionNotSupported);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,8 +11,11 @@
|
||||||
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.XPath;
|
using System.Xml.XPath;
|
||||||
using Test.Cryptography;
|
using Test.Cryptography;
|
||||||
|
@ -1587,6 +1590,127 @@ namespace System.Security.Cryptography.Xml.Tests
|
||||||
Assert.Throws<FormatException>(() => sign.CheckSignature(new HMACSHA1("no clue"u8.ToArray())));
|
Assert.Throws<FormatException>(() => sign.CheckSignature(new HMACSHA1("no clue"u8.ToArray())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[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 = 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.False(listenerContacted, "listenerContacted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
tokenSource.Cancel();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
listener.Stop();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
((IDisposable)listener).Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task 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]
|
[Fact]
|
||||||
public void CoreFxSignedXmlUsesSha256ByDefault()
|
public void CoreFxSignedXmlUsesSha256ByDefault()
|
||||||
{
|
{
|
||||||
|
|
|
@ -948,11 +948,13 @@ namespace System.Xml
|
||||||
{
|
{
|
||||||
protected XmlResolver() { }
|
protected XmlResolver() { }
|
||||||
public virtual System.Net.ICredentials Credentials { set { } }
|
public virtual System.Net.ICredentials Credentials { set { } }
|
||||||
|
public static System.Xml.XmlResolver ThrowingResolver { get { throw null; } }
|
||||||
public abstract object? GetEntity(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn);
|
public abstract object? GetEntity(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn);
|
||||||
public virtual System.Threading.Tasks.Task<object> GetEntityAsync(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn) { throw null; }
|
public virtual System.Threading.Tasks.Task<object> GetEntityAsync(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn) { throw null; }
|
||||||
public virtual System.Uri ResolveUri(System.Uri? baseUri, string? relativeUri) { throw null; }
|
public virtual System.Uri ResolveUri(System.Uri? baseUri, string? relativeUri) { throw null; }
|
||||||
public virtual bool SupportsType(System.Uri absoluteUri, System.Type? type) { throw null; }
|
public virtual bool SupportsType(System.Uri absoluteUri, System.Type? type) { throw null; }
|
||||||
}
|
}
|
||||||
|
[System.ObsoleteAttribute("XmlSecureResolver is obsolete. Use XmlResolver.ThrowingResolver instead when attempting to forbid XML external entity resolution.", DiagnosticId = "SYSLIB0047", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
|
||||||
public partial class XmlSecureResolver : System.Xml.XmlResolver
|
public partial class XmlSecureResolver : System.Xml.XmlResolver
|
||||||
{
|
{
|
||||||
public XmlSecureResolver(System.Xml.XmlResolver resolver, string? securityUrl) { }
|
public XmlSecureResolver(System.Xml.XmlResolver resolver, string? securityUrl) { }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue