diff --git a/.github/workflows/markdownlint.yml b/.github/workflows/markdownlint.yml
index 79a42573425f2f..b9f50eb27fd055 100644
--- a/.github/workflows/markdownlint.yml
+++ b/.github/workflows/markdownlint.yml
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v6
- name: Use Node.js
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v6
with:
- node-version: 16.x
+ node-version: '22.x'
- name: Run Markdownlint
run: |
echo "::add-matcher::.github/workflows/markdownlint-problem-matcher.json"
diff --git a/NuGet.config b/NuGet.config
index 231d0aff39ca36..c522e68ce07f8e 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -9,7 +9,7 @@
-
+
diff --git a/docs/workflow/building/coreclr/cross-building.md b/docs/workflow/building/coreclr/cross-building.md
index 7bbe28abb64105..eb6f555f99042e 100644
--- a/docs/workflow/building/coreclr/cross-building.md
+++ b/docs/workflow/building/coreclr/cross-building.md
@@ -155,7 +155,7 @@ docker run --rm \
-v :/runtime \
-w /runtime \
-e ROOTFS_DIR=/crossrootfs/arm64 \
- mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64 \
+ mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net8.0-cross-arm64 \
./build.sh --subset clr --cross --arch arm64
```
diff --git a/docs/workflow/building/coreclr/linux-instructions.md b/docs/workflow/building/coreclr/linux-instructions.md
index 0d28067fe7843c..48cd40fa4bac7e 100644
--- a/docs/workflow/building/coreclr/linux-instructions.md
+++ b/docs/workflow/building/coreclr/linux-instructions.md
@@ -53,7 +53,7 @@ To do cross-building using Docker, you need to use either specific images design
This table of images might often become stale as we change our images as our requirements change. The images used for our official builds can be found in [the pipeline resources](/eng/pipelines/common/templates/pipeline-with-resources.yml) of our Azure DevOps builds under the `container` key of the platform you plan to build. These image tags don't include version numbers, and our build infrastructure will automatically use the latest version of the image. You can ensure you are using the latest version by using `docker pull`, for example:
```
-docker pull mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64
+docker pull mcr.microsoft.com/dotnet-buildtools/prereqs:azurelinux-3.0-net8.0-cross-arm64
```
All official builds are cross-builds with a rootfs for the target OS, and will use the clang version available on the container.
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index c2c1678b9f0571..ed80ce1ada6d68 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -90,13 +90,13 @@
dc12f3e6ccb3fd7b76c0d5ee3365e6b58d796de0
-
+
https://github.com/dotnet/emsdk
- d9d29898aa3613261a63ef89f54f7218a99a77c9
+ 925a4f472f7e1c6d3bcb5092d28d952f90cc6237
-
+
https://github.com/dotnet/emsdk
- d9d29898aa3613261a63ef89f54f7218a99a77c9
+ 925a4f472f7e1c6d3bcb5092d28d952f90cc6237
diff --git a/eng/Versions.props b/eng/Versions.props
index d45445daecd2df..564eb4eed4c7e3 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,11 +1,11 @@
- 8.0.26
+ 8.0.27
8
0
- 26
+ 27
8.0.100
7.0.20
6.0.36
@@ -233,7 +233,7 @@
8.0.0-rtm.25625.2
- 2.4.16
+ 2.4.17
16.0.5-alpha.1.25311.1
16.0.5-alpha.1.25311.1
@@ -253,7 +253,7 @@
Note: when the name is updated, make sure to update dependency name in eng/pipelines/common/xplat-setup.yml
like - DarcDependenciesChanged.Microsoft_NET_Workload_Emscripten_Current_Manifest-8_0_100_Transport
-->
- 8.0.26
+ 8.0.27
$(MicrosoftNETWorkloadEmscriptenCurrentManifest80100Version)
true
- false
- 2
+ true
+ 3
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/.
Commonly Used Types:
@@ -101,6 +101,7 @@ System.Security.Cryptography.Xml.XmlLicenseTransform
+
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalizationDispatcher.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalizationDispatcher.cs
index ae5ff3e1c0c6fc..5813a99c35ed80 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalizationDispatcher.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalizationDispatcher.cs
@@ -10,15 +10,32 @@ namespace System.Security.Cryptography.Xml
// implement ICanonicalizableNode; so a manual dispatch is sometimes necessary.
internal static class CanonicalizationDispatcher
{
+ [ThreadStatic]
+ private static int t_depth;
+
public static void Write(XmlNode node, StringBuilder strBuilder, DocPosition docPos, AncestralNamespaceContextManager anc)
{
- if (node is ICanonicalizableNode)
+ int maxDepth = LocalAppContextSwitches.DangerousMaxRecursionDepth;
+ if (maxDepth > 0 && t_depth > maxDepth)
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_MaxDepthExceeded);
+ }
+
+ t_depth++;
+ try
{
- ((ICanonicalizableNode)node).Write(strBuilder, docPos, anc);
+ if (node is ICanonicalizableNode canonicalizableNode)
+ {
+ canonicalizableNode.Write(strBuilder, docPos, anc);
+ }
+ else
+ {
+ WriteGenericNode(node, strBuilder, docPos, anc);
+ }
}
- else
+ finally
{
- WriteGenericNode(node, strBuilder, docPos, anc);
+ t_depth--;
}
}
@@ -38,13 +55,27 @@ public static void WriteGenericNode(XmlNode node, StringBuilder strBuilder, DocP
public static void WriteHash(XmlNode node, HashAlgorithm hash, DocPosition docPos, AncestralNamespaceContextManager anc)
{
- if (node is ICanonicalizableNode)
+ int maxDepth = LocalAppContextSwitches.DangerousMaxRecursionDepth;
+ if (maxDepth > 0 && t_depth > maxDepth)
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_MaxDepthExceeded);
+ }
+
+ t_depth++;
+ try
{
- ((ICanonicalizableNode)node).WriteHash(hash, docPos, anc);
+ if (node is ICanonicalizableNode canonicalizableNode)
+ {
+ canonicalizableNode.WriteHash(hash, docPos, anc);
+ }
+ else
+ {
+ WriteHashGenericNode(node, hash, docPos, anc);
+ }
}
- else
+ finally
{
- WriteHashGenericNode(node, hash, docPos, anc);
+ t_depth--;
}
}
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs
index 3de83fe10ebc08..a1982910cc18fc 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs
@@ -17,55 +17,63 @@ public override void LoadXml(XmlElement value)
throw new ArgumentNullException(nameof(value));
}
- XmlNamespaceManager nsm = new XmlNamespaceManager(value.OwnerDocument.NameTable);
- nsm.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
- nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
-
- Id = Utils.GetAttribute(value, "Id", EncryptedXml.XmlEncNamespaceUrl);
- Type = Utils.GetAttribute(value, "Type", EncryptedXml.XmlEncNamespaceUrl);
- MimeType = Utils.GetAttribute(value, "MimeType", EncryptedXml.XmlEncNamespaceUrl);
- Encoding = Utils.GetAttribute(value, "Encoding", EncryptedXml.XmlEncNamespaceUrl);
-
- XmlNode? encryptionMethodNode = value.SelectSingleNode("enc:EncryptionMethod", nsm);
-
- // EncryptionMethod
- EncryptionMethod = new EncryptionMethod();
- if (encryptionMethodNode != null)
- EncryptionMethod.LoadXml((encryptionMethodNode as XmlElement)!);
-
- // Key Info
- KeyInfo = new KeyInfo();
- XmlNode? keyInfoNode = value.SelectSingleNode("ds:KeyInfo", nsm);
- if (keyInfoNode != null)
- KeyInfo.LoadXml((keyInfoNode as XmlElement)!);
-
- // CipherData
- XmlNode? cipherDataNode = value.SelectSingleNode("enc:CipherData", nsm);
- if (cipherDataNode == null)
- throw new CryptographicException(SR.Cryptography_Xml_MissingCipherData);
-
- CipherData = new CipherData();
- CipherData.LoadXml((cipherDataNode as XmlElement)!);
-
- // EncryptionProperties
- XmlNode? encryptionPropertiesNode = value.SelectSingleNode("enc:EncryptionProperties", nsm);
- if (encryptionPropertiesNode != null)
+ IncrementLoadXmlCurrentThreadDepth();
+ try
{
- // Select the EncryptionProperty elements inside the EncryptionProperties element
- XmlNodeList? encryptionPropertyNodes = encryptionPropertiesNode.SelectNodes("enc:EncryptionProperty", nsm);
- if (encryptionPropertyNodes != null)
+ XmlNamespaceManager nsm = new XmlNamespaceManager(value.OwnerDocument.NameTable);
+ nsm.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
+ nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
+
+ Id = Utils.GetAttribute(value, "Id", EncryptedXml.XmlEncNamespaceUrl);
+ Type = Utils.GetAttribute(value, "Type", EncryptedXml.XmlEncNamespaceUrl);
+ MimeType = Utils.GetAttribute(value, "MimeType", EncryptedXml.XmlEncNamespaceUrl);
+ Encoding = Utils.GetAttribute(value, "Encoding", EncryptedXml.XmlEncNamespaceUrl);
+
+ XmlNode? encryptionMethodNode = value.SelectSingleNode("enc:EncryptionMethod", nsm);
+
+ // EncryptionMethod
+ EncryptionMethod = new EncryptionMethod();
+ if (encryptionMethodNode != null)
+ EncryptionMethod.LoadXml((encryptionMethodNode as XmlElement)!);
+
+ // Key Info
+ KeyInfo = new KeyInfo();
+ XmlNode? keyInfoNode = value.SelectSingleNode("ds:KeyInfo", nsm);
+ if (keyInfoNode != null)
+ KeyInfo.LoadXml((keyInfoNode as XmlElement)!);
+
+ // CipherData
+ XmlNode? cipherDataNode = value.SelectSingleNode("enc:CipherData", nsm);
+ if (cipherDataNode == null)
+ throw new CryptographicException(SR.Cryptography_Xml_MissingCipherData);
+
+ CipherData = new CipherData();
+ CipherData.LoadXml((cipherDataNode as XmlElement)!);
+
+ // EncryptionProperties
+ XmlNode? encryptionPropertiesNode = value.SelectSingleNode("enc:EncryptionProperties", nsm);
+ if (encryptionPropertiesNode != null)
{
- foreach (XmlNode node in encryptionPropertyNodes)
+ // Select the EncryptionProperty elements inside the EncryptionProperties element
+ XmlNodeList? encryptionPropertyNodes = encryptionPropertiesNode.SelectNodes("enc:EncryptionProperty", nsm);
+ if (encryptionPropertyNodes != null)
{
- EncryptionProperty ep = new EncryptionProperty();
- ep.LoadXml((node as XmlElement)!);
- EncryptionProperties.Add(ep);
+ foreach (XmlNode node in encryptionPropertyNodes)
+ {
+ EncryptionProperty ep = new EncryptionProperty();
+ ep.LoadXml((node as XmlElement)!);
+ EncryptionProperties.Add(ep);
+ }
}
}
- }
- // Save away the cached value
- _cachedXml = value;
+ // Save away the cached value
+ _cachedXml = value;
+ }
+ finally
+ {
+ DecrementLoadXmlCurrentThreadDepth();
+ }
}
public override XmlElement GetXml()
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs
index 3cd2a7bc0a35ee..1762844daf1726 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs
@@ -56,91 +56,99 @@ public override void LoadXml(XmlElement value)
throw new ArgumentNullException(nameof(value));
}
- XmlNamespaceManager nsm = new XmlNamespaceManager(value.OwnerDocument.NameTable);
- nsm.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
- nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
-
- Id = Utils.GetAttribute(value, "Id", EncryptedXml.XmlEncNamespaceUrl);
- Type = Utils.GetAttribute(value, "Type", EncryptedXml.XmlEncNamespaceUrl);
- MimeType = Utils.GetAttribute(value, "MimeType", EncryptedXml.XmlEncNamespaceUrl);
- Encoding = Utils.GetAttribute(value, "Encoding", EncryptedXml.XmlEncNamespaceUrl);
- Recipient = Utils.GetAttribute(value, "Recipient", EncryptedXml.XmlEncNamespaceUrl);
-
- XmlNode? encryptionMethodNode = value.SelectSingleNode("enc:EncryptionMethod", nsm);
-
- // EncryptionMethod
- EncryptionMethod = new EncryptionMethod();
- if (encryptionMethodNode != null)
- EncryptionMethod.LoadXml((encryptionMethodNode as XmlElement)!);
-
- // Key Info
- KeyInfo = new KeyInfo();
- XmlNode? keyInfoNode = value.SelectSingleNode("ds:KeyInfo", nsm);
- if (keyInfoNode != null)
- KeyInfo.LoadXml((keyInfoNode as XmlElement)!);
-
- // CipherData
- XmlNode? cipherDataNode = value.SelectSingleNode("enc:CipherData", nsm);
- if (cipherDataNode == null)
- throw new CryptographicException(SR.Cryptography_Xml_MissingCipherData);
-
- CipherData = new CipherData();
- CipherData.LoadXml((cipherDataNode as XmlElement)!);
-
- // EncryptionProperties
- XmlNode? encryptionPropertiesNode = value.SelectSingleNode("enc:EncryptionProperties", nsm);
- if (encryptionPropertiesNode != null)
+ IncrementLoadXmlCurrentThreadDepth();
+ try
{
- // Select the EncryptionProperty elements inside the EncryptionProperties element
- XmlNodeList? encryptionPropertyNodes = encryptionPropertiesNode.SelectNodes("enc:EncryptionProperty", nsm);
- if (encryptionPropertyNodes != null)
+ XmlNamespaceManager nsm = new XmlNamespaceManager(value.OwnerDocument.NameTable);
+ nsm.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
+ nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
+
+ Id = Utils.GetAttribute(value, "Id", EncryptedXml.XmlEncNamespaceUrl);
+ Type = Utils.GetAttribute(value, "Type", EncryptedXml.XmlEncNamespaceUrl);
+ MimeType = Utils.GetAttribute(value, "MimeType", EncryptedXml.XmlEncNamespaceUrl);
+ Encoding = Utils.GetAttribute(value, "Encoding", EncryptedXml.XmlEncNamespaceUrl);
+ Recipient = Utils.GetAttribute(value, "Recipient", EncryptedXml.XmlEncNamespaceUrl);
+
+ XmlNode? encryptionMethodNode = value.SelectSingleNode("enc:EncryptionMethod", nsm);
+
+ // EncryptionMethod
+ EncryptionMethod = new EncryptionMethod();
+ if (encryptionMethodNode != null)
+ EncryptionMethod.LoadXml((encryptionMethodNode as XmlElement)!);
+
+ // Key Info
+ KeyInfo = new KeyInfo();
+ XmlNode? keyInfoNode = value.SelectSingleNode("ds:KeyInfo", nsm);
+ if (keyInfoNode != null)
+ KeyInfo.LoadXml((keyInfoNode as XmlElement)!);
+
+ // CipherData
+ XmlNode? cipherDataNode = value.SelectSingleNode("enc:CipherData", nsm);
+ if (cipherDataNode == null)
+ throw new CryptographicException(SR.Cryptography_Xml_MissingCipherData);
+
+ CipherData = new CipherData();
+ CipherData.LoadXml((cipherDataNode as XmlElement)!);
+
+ // EncryptionProperties
+ XmlNode? encryptionPropertiesNode = value.SelectSingleNode("enc:EncryptionProperties", nsm);
+ if (encryptionPropertiesNode != null)
{
- foreach (XmlNode node in encryptionPropertyNodes)
+ // Select the EncryptionProperty elements inside the EncryptionProperties element
+ XmlNodeList? encryptionPropertyNodes = encryptionPropertiesNode.SelectNodes("enc:EncryptionProperty", nsm);
+ if (encryptionPropertyNodes != null)
{
- EncryptionProperty ep = new EncryptionProperty();
- ep.LoadXml((node as XmlElement)!);
- EncryptionProperties.Add(ep);
+ foreach (XmlNode node in encryptionPropertyNodes)
+ {
+ EncryptionProperty ep = new EncryptionProperty();
+ ep.LoadXml((node as XmlElement)!);
+ EncryptionProperties.Add(ep);
+ }
}
}
- }
- // CarriedKeyName
- XmlNode? carriedKeyNameNode = value.SelectSingleNode("enc:CarriedKeyName", nsm);
- if (carriedKeyNameNode != null)
- {
- CarriedKeyName = carriedKeyNameNode.InnerText;
- }
+ // CarriedKeyName
+ XmlNode? carriedKeyNameNode = value.SelectSingleNode("enc:CarriedKeyName", nsm);
+ if (carriedKeyNameNode != null)
+ {
+ CarriedKeyName = carriedKeyNameNode.InnerText;
+ }
- // ReferenceList
- XmlNode? referenceListNode = value.SelectSingleNode("enc:ReferenceList", nsm);
- if (referenceListNode != null)
- {
- // Select the DataReference elements inside the ReferenceList element
- XmlNodeList? dataReferenceNodes = referenceListNode.SelectNodes("enc:DataReference", nsm);
- if (dataReferenceNodes != null)
+ // ReferenceList
+ XmlNode? referenceListNode = value.SelectSingleNode("enc:ReferenceList", nsm);
+ if (referenceListNode != null)
{
- foreach (XmlNode node in dataReferenceNodes)
+ // Select the DataReference elements inside the ReferenceList element
+ XmlNodeList? dataReferenceNodes = referenceListNode.SelectNodes("enc:DataReference", nsm);
+ if (dataReferenceNodes != null)
{
- DataReference dr = new DataReference();
- dr.LoadXml((node as XmlElement)!);
- ReferenceList.Add(dr);
+ foreach (XmlNode node in dataReferenceNodes)
+ {
+ DataReference dr = new DataReference();
+ dr.LoadXml((node as XmlElement)!);
+ ReferenceList.Add(dr);
+ }
}
- }
- // Select the KeyReference elements inside the ReferenceList element
- XmlNodeList? keyReferenceNodes = referenceListNode.SelectNodes("enc:KeyReference", nsm);
- if (keyReferenceNodes != null)
- {
- foreach (XmlNode node in keyReferenceNodes)
+ // Select the KeyReference elements inside the ReferenceList element
+ XmlNodeList? keyReferenceNodes = referenceListNode.SelectNodes("enc:KeyReference", nsm);
+ if (keyReferenceNodes != null)
{
- KeyReference kr = new KeyReference();
- kr.LoadXml((node as XmlElement)!);
- ReferenceList.Add(kr);
+ foreach (XmlNode node in keyReferenceNodes)
+ {
+ KeyReference kr = new KeyReference();
+ kr.LoadXml((node as XmlElement)!);
+ ReferenceList.Add(kr);
+ }
}
}
- }
- // Save away the cached value
- _cachedXml = value;
+ // Save away the cached value
+ _cachedXml = value;
+ }
+ finally
+ {
+ DecrementLoadXmlCurrentThreadDepth();
+ }
}
public override XmlElement GetXml()
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs
index 29aa30afacfec7..bfcc117f1d0a46 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Xml;
@@ -8,6 +9,9 @@ namespace System.Security.Cryptography.Xml
{
public abstract class EncryptedType
{
+ [ThreadStatic]
+ private static int t_depth;
+
private string? _id;
private string? _type;
private string? _mimeType;
@@ -74,6 +78,24 @@ public KeyInfo KeyInfo
set => _keyInfo = value;
}
+ internal static void IncrementLoadXmlCurrentThreadDepth()
+ {
+ Debug.Assert(t_depth >= 0, "LoadXml current thread depth is negative.");
+ int maxDepth = LocalAppContextSwitches.DangerousMaxRecursionDepth;
+ if (maxDepth > 0 && t_depth > maxDepth)
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_MaxDepthExceeded);
+ }
+
+ t_depth++;
+ }
+
+ internal static void DecrementLoadXmlCurrentThreadDepth()
+ {
+ Debug.Assert(t_depth > 0, "LoadXml current thread depth is already 0.");
+ t_depth--;
+ }
+
public virtual EncryptionMethod? EncryptionMethod
{
get { return _encryptionMethod; }
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs
index 1e42b3a73ac9ee..05d0fbb8d18eac 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Security.Cryptography.X509Certificates;
@@ -73,6 +74,9 @@ public class EncryptedXml
private int _xmlDsigSearchDepthCounter;
private int _xmlDsigSearchDepth;
+ // Built in transform algorithm URIs
+ private static IList? s_defaultSafeTransformMethods;
+
//
// public constructors
//
@@ -212,6 +216,11 @@ private byte[] GetCipherValue(CipherData cipherData)
{
throw new CryptographicException(SR.Cryptography_Xml_UriNotSupported);
}
+ if (!ReferenceUsesSafeTransformMethods(cipherData.CipherReference))
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_NotSupportedCryptographicTransform);
+ }
+
decInputStream = tc.TransformToOctetStream(_document, _xmlResolver, baseUri);
}
else if (cipherData.CipherReference.Uri[0] == '#')
@@ -230,6 +239,11 @@ private byte[] GetCipherValue(CipherData cipherData)
{
throw new CryptographicException(SR.Cryptography_Xml_UriNotSupported);
}
+ if (!ReferenceUsesSafeTransformMethods(cipherData.CipherReference))
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_NotSupportedCryptographicTransform);
+ }
+
decInputStream = tc.TransformToOctetStream(inputStream, _xmlResolver, baseUri);
}
else
@@ -1019,5 +1033,69 @@ public static byte[] DecryptKey(byte[] keyData, RSA rsa, bool useOAEP)
return rsaDeformatter.DecryptKeyExchange(keyData);
}
}
+
+ private static bool ReferenceUsesSafeTransformMethods(CipherReference reference)
+ {
+ // If the app context switch to enforce safe transforms is not enabled,
+ // then we consider all transforms to be safe.
+ if (LocalAppContextSwitches.AllowDangerousEncryptedXmlTransforms)
+ {
+ return true;
+ }
+
+ TransformChain transformChain = reference.TransformChain;
+ int transformCount = transformChain.Count;
+
+ for (int i = 0; i < transformCount; i++)
+ {
+ Transform transform = transformChain[i];
+
+ if (!IsSafeTransform(transform.Algorithm!))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static bool IsSafeTransform(string transformAlgorithm)
+ {
+ foreach (string safeAlgorithm in DefaultSafeTransformMethods)
+ {
+ if (string.Equals(safeAlgorithm, transformAlgorithm, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static IList DefaultSafeTransformMethods
+ {
+ get
+ {
+ if (s_defaultSafeTransformMethods == null)
+ {
+ List safeAlgorithms = new List();
+
+ // Built in canonicalization algorithms
+ safeAlgorithms.Add(SignedXml.XmlDsigC14NTransformUrl);
+ safeAlgorithms.Add(SignedXml.XmlDsigC14NWithCommentsTransformUrl);
+ safeAlgorithms.Add(SignedXml.XmlDsigExcC14NTransformUrl);
+ safeAlgorithms.Add(SignedXml.XmlDsigExcC14NWithCommentsTransformUrl);
+
+ // Other built in transform algorithms
+ safeAlgorithms.Add(SignedXml.XmlDsigBase64TransformUrl);
+ safeAlgorithms.Add(SignedXml.XmlLicenseTransformUrl);
+ safeAlgorithms.Add(SignedXml.XmlDecryptionTransformUrl);
+
+ s_defaultSafeTransformMethods = safeAlgorithms;
+ }
+
+ return s_defaultSafeTransformMethods;
+ }
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs
index 2beaa3eb31dbbb..82687d987f1330 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs
@@ -67,48 +67,56 @@ public void LoadXml(XmlElement value)
throw new ArgumentNullException(nameof(value));
}
- XmlElement keyInfoElement = value;
- _id = Utils.GetAttribute(keyInfoElement, "Id", SignedXml.XmlDsigNamespaceUrl);
- if (!Utils.VerifyAttributes(keyInfoElement, "Id"))
- throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "KeyInfo");
-
- XmlNode? child = keyInfoElement.FirstChild;
- while (child != null)
+ EncryptedType.IncrementLoadXmlCurrentThreadDepth();
+ try
{
- XmlElement? elem = child as XmlElement;
- if (elem != null)
+ XmlElement keyInfoElement = value;
+ _id = Utils.GetAttribute(keyInfoElement, "Id", SignedXml.XmlDsigNamespaceUrl);
+ if (!Utils.VerifyAttributes(keyInfoElement, "Id"))
+ throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "KeyInfo");
+
+ XmlNode? child = keyInfoElement.FirstChild;
+ while (child != null)
{
- // Create the right type of KeyInfoClause; we use a combination of the namespace and tag name (local name)
- string kicString = elem.NamespaceURI + " " + elem.LocalName;
- // Special-case handling for KeyValue -- we have to go one level deeper
- if (kicString == "http://www.w3.org/2000/09/xmldsig# KeyValue")
+ XmlElement? elem = child as XmlElement;
+ if (elem != null)
{
- if (!Utils.VerifyAttributes(elem, (string[]?)null))
+ // Create the right type of KeyInfoClause; we use a combination of the namespace and tag name (local name)
+ string kicString = elem.NamespaceURI + " " + elem.LocalName;
+ // Special-case handling for KeyValue -- we have to go one level deeper
+ if (kicString == "http://www.w3.org/2000/09/xmldsig# KeyValue")
{
- throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "KeyInfo/KeyValue");
- }
- XmlNodeList nodeList2 = elem.ChildNodes;
- foreach (XmlNode node2 in nodeList2)
- {
- XmlElement? elem2 = node2 as XmlElement;
- if (elem2 != null)
+ if (!Utils.VerifyAttributes(elem, (string[]?)null))
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_InvalidElement, "KeyInfo/KeyValue");
+ }
+ XmlNodeList nodeList2 = elem.ChildNodes;
+ foreach (XmlNode node2 in nodeList2)
{
- kicString += "/" + elem2.LocalName;
- break;
+ XmlElement? elem2 = node2 as XmlElement;
+ if (elem2 != null)
+ {
+ kicString += "/" + elem2.LocalName;
+ break;
+ }
}
}
- }
- KeyInfoClause? keyInfoClause = CryptoHelpers.CreateNonTransformFromName(kicString);
- // if we don't know what kind of KeyInfoClause we're looking at, use a generic KeyInfoNode:
- keyInfoClause ??= new KeyInfoNode();
+ KeyInfoClause? keyInfoClause = CryptoHelpers.CreateNonTransformFromName(kicString);
+ // if we don't know what kind of KeyInfoClause we're looking at, use a generic KeyInfoNode:
+ keyInfoClause ??= new KeyInfoNode();
- // Ask the create clause to fill itself with the corresponding XML
- keyInfoClause.LoadXml(elem);
- // Add it to our list of KeyInfoClauses
- AddClause(keyInfoClause);
+ // Ask the create clause to fill itself with the corresponding XML
+ keyInfoClause.LoadXml(elem);
+ // Add it to our list of KeyInfoClauses
+ AddClause(keyInfoClause);
+ }
+ child = child.NextSibling;
}
- child = child.NextSibling;
+ }
+ finally
+ {
+ EncryptedType.DecrementLoadXmlCurrentThreadDepth();
}
}
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/LocalAppContextSwitches.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/LocalAppContextSwitches.cs
new file mode 100644
index 00000000000000..16a7a9f95bcde8
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/LocalAppContextSwitches.cs
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Globalization;
+
+namespace System
+{
+ internal static partial class LocalAppContextSwitches
+ {
+ internal const int DefaultMaxDecryptionDepth = 64;
+ internal const string DangerousMaxRecursionDepthAppContextSwitch = "System.Security.Cryptography.Xml.DangerousMaxRecursionDepth";
+ internal const string AllowDangerousEncryptedXmlTransformsAppContextSwitch = "System.Security.Cryptography.Xml.AllowDangerousEncryptedXmlTransforms";
+
+ ///
+ /// Gets the maximum recursion depth for recursive XML operations.
+ /// Configurable via AppContext data "System.Security.Cryptography.Xml.DangerousMaxRecursionDepth".
+ /// Default value is 64. A value of 0 means infinite (no limit).
+ ///
+ internal static int DangerousMaxRecursionDepth { get; } =
+ GetInt32Config(DangerousMaxRecursionDepthAppContextSwitch, DefaultMaxDecryptionDepth, allowNegative: false);
+
+ ///
+ /// Gets whether to enforce safe transforms for XML encryption by default.
+ /// Configurable via AppContext switch "System.Security.Cryptography.Xml.AllowDangerousEncryptedXmlTransforms".
+ /// Default value is false.
+ ///
+ internal static bool AllowDangerousEncryptedXmlTransforms { get; } =
+ GetBooleanConfig(AllowDangerousEncryptedXmlTransformsAppContextSwitch, defaultValue: false);
+
+ ///
+ /// Gets an integer configuration value from AppContext data.
+ ///
+ /// The AppContext data key name.
+ /// The default value if not configured or invalid.
+ /// Whether to allow negative values.
+ /// The configured value or the default.
+ private static int GetInt32Config(string appContextName, int defaultValue, bool allowNegative = true)
+ {
+ object? data = AppContext.GetData(appContextName);
+
+ if (data is null)
+ {
+ return defaultValue;
+ }
+
+ int value;
+
+ try
+ {
+ value = Convert.ToInt32(data, CultureInfo.InvariantCulture);
+ }
+ catch
+ {
+ return defaultValue;
+ }
+
+ return (allowNegative || value >= 0) ? value : defaultValue;
+ }
+
+ ///
+ /// Gets a boolean configuration value from AppContext switch.
+ ///
+ /// The AppContext switch name.
+ /// The default value if not configured or invalid.
+ /// The configured value or the default.
+ private static bool GetBooleanConfig(string appContextName, bool defaultValue)
+ {
+ if (AppContext.TryGetSwitch(appContextName, out bool isEnabled))
+ {
+ return isEnabled;
+ }
+
+ return defaultValue;
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs
index 9633e0111c71a5..fc3326bc610dc3 100644
--- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs
+++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml;
@@ -221,15 +222,19 @@ private void ProcessElementRecursively(XmlNodeList encryptedDatas)
{
if (encryptedDatas == null || encryptedDatas.Count == 0)
return;
- Queue encryptedDatasQueue = new Queue();
+ int maxDepth = LocalAppContextSwitches.DangerousMaxRecursionDepth;
+ Queue encryptedDatasQueue = new();
foreach (XmlNode value in encryptedDatas)
{
- encryptedDatasQueue.Enqueue(value);
+ encryptedDatasQueue.Enqueue(new(value, depth: 0));
}
- XmlNode? node = encryptedDatasQueue.Dequeue() as XmlNode;
- while (node != null)
+
+ while (encryptedDatasQueue.Count > 0)
{
- XmlElement? encryptedDataElement = node as XmlElement;
+ ProcessElementWorkItem workItem = encryptedDatasQueue.Dequeue();
+ XmlElement? encryptedDataElement = workItem.Element as XmlElement;
+ int depth = workItem.Depth;
+
if (encryptedDataElement != null && encryptedDataElement.LocalName == "EncryptedData" &&
encryptedDataElement.NamespaceURI == EncryptedXml.XmlEncNamespaceUrl)
{
@@ -246,17 +251,19 @@ private void ProcessElementRecursively(XmlNodeList encryptedDatas)
XmlNodeList nodes = child.SelectNodes("//enc:EncryptedData", _nsm!)!;
if (nodes.Count > 0)
{
+ if (maxDepth > 0 && depth > maxDepth)
+ {
+ throw new CryptographicException(SR.Cryptography_Xml_MaxDepthExceeded);
+ }
+
foreach (XmlNode value in nodes)
{
- encryptedDatasQueue.Enqueue(value);
+ encryptedDatasQueue.Enqueue(new(value, depth + 1));
}
}
}
}
}
- if (encryptedDatasQueue.Count == 0)
- break;
- node = encryptedDatasQueue.Dequeue() as XmlNode;
}
}
@@ -277,5 +284,11 @@ public override object GetOutput(Type type)
else
throw new ArgumentException(SR.Cryptography_Xml_TransformIncorrectInputType, nameof(type));
}
+
+ private readonly struct ProcessElementWorkItem(XmlNode element, int depth)
+ {
+ public readonly XmlNode Element = element;
+ public readonly int Depth = depth;
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlSample4.xml b/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlSample4.xml
new file mode 100644
index 00000000000000..585a61ecdbe527
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography.Xml/tests/EncryptedXmlSample4.xml
@@ -0,0 +1,1994 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+