Skip to content

XmlDecryptionTransform throws NullReferenceException for sibling EncryptedData elements #134019

Description

@PranavSenthilnathan

Description

XmlDecryptionTransform.GetOutput() throws a NullReferenceException when the input document contains two sibling EncryptedData elements.

Reproduction Steps

using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;

XmlDocument document = new();
document.LoadXml("<root><first>one</first><second>two</second></root>");

using Aes key = Aes.Create();
EncryptedXml encryptedXml = new(document);
encryptedXml.AddKeyNameMapping("key", key);

EncryptElement("first");
EncryptElement("second");

XmlDecryptionTransform transform = new()
{
    EncryptedXml = encryptedXml,
};

transform.LoadInput(document);
transform.GetOutput();

void EncryptElement(string name)
{
    XmlElement element = (XmlElement)document.DocumentElement!.SelectSingleNode(name)!;
    EncryptedData encryptedData = encryptedXml.Encrypt(element, "key");
    EncryptedXml.ReplaceElement(element, encryptedData, content: false);
}

Expected behavior

Both sibling elements should be decrypted and GetOutput() should return the transformed document without throwing.

Actual behavior

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Security.Cryptography.Xml.XmlDecryptionTransform.ReplaceEncryptedData(XmlElement encryptedDataElement, Byte[] decrypted) in XmlDecryptionTransform.cs:line 176
   at System.Security.Cryptography.Xml.XmlDecryptionTransform.ProcessEncryptedDataItem(XmlElement encryptedDataElement) in XmlDecryptionTransform.cs:line 211
   at System.Security.Cryptography.Xml.XmlDecryptionTransform.ProcessElementRecursively(XmlNodeList encryptedDatas) in XmlDecryptionTransform.cs:line 245
   at System.Security.Cryptography.Xml.XmlDecryptionTransform.GetOutput() in XmlDecryptionTransform.cs:line 276
   at Program.<Main>$(String[] args) in Program.cs:line 25

Regression?

Unknown.

Known Workarounds

N/A

Configuration

N/A

Other information

ProcessElementRecursively initially queues both sibling EncryptedData nodes. After decrypting the first node, this expression is evaluated from the replacement child:

child.SelectNodes("//enc:EncryptedData", _nsm!)

Because the XPath begins with //, it searches from the document root and finds the second sibling, even though that node is already in the queue. The second node is therefore queued twice.

The original queue entry decrypts and replaces the second node, detaching it from the document. When the duplicate entry is subsequently processed, encryptedDataElement.ParentNode is null. ReplaceEncryptedData dereferences that null parent and throws the NullReferenceException.

Note

This issue was drafted with GitHub Copilot.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions