| File: System\Security\Cryptography\Xml\XmlLicenseTransform.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography.Xml\src\System.Security.Cryptography.Xml.csproj (System.Security.Cryptography.Xml) |
// 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.CodeAnalysis; using System.IO; using System.Xml; namespace System.Security.Cryptography.Xml { [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public class XmlLicenseTransform : Transform { private readonly Type[] _inputTypes = { typeof(XmlDocument) }; private readonly Type[] _outputTypes = { typeof(XmlDocument) }; private XmlNamespaceManager? _namespaceManager; private XmlDocument? _license; private IRelDecryptor? _relDecryptor; // work around https://github.com/dotnet/runtime/issues/81864 by splitting these into a separate class. internal static class Consts { internal const string ElementIssuer = "issuer"; internal const string NamespaceUriCore = "urn:mpeg:mpeg21:2003:01-REL-R-NS"; } public XmlLicenseTransform() { Algorithm = SignedXml.XmlLicenseTransformUrl; } public override Type[] InputTypes { get { return _inputTypes; } } public override Type[] OutputTypes { get { return _outputTypes; } } public IRelDecryptor? Decryptor { get { return _relDecryptor; } set { _relDecryptor = value; } } private void DecryptEncryptedGrants(XmlNodeList encryptedGrantList) { XmlElement? encryptionMethod; XmlElement? keyInfo; XmlElement? cipherData; EncryptionMethod encryptionMethodObj; KeyInfo keyInfoObj; CipherData cipherDataObj; for (int i = 0, count = encryptedGrantList.Count; i < count; i++) { encryptionMethod = encryptedGrantList[i]!.SelectSingleNode("//r:encryptedGrant/enc:EncryptionMethod", _namespaceManager!) as XmlElement; keyInfo = encryptedGrantList[i]!.SelectSingleNode("//r:encryptedGrant/dsig:KeyInfo", _namespaceManager!) as XmlElement; cipherData = encryptedGrantList[i]!.SelectSingleNode("//r:encryptedGrant/enc:CipherData", _namespaceManager!) as XmlElement; if ((encryptionMethod != null) && (keyInfo != null) && (cipherData != null)) { encryptionMethodObj = new EncryptionMethod(); keyInfoObj = new KeyInfo(); cipherDataObj = new CipherData(); encryptionMethodObj.LoadXml(encryptionMethod); keyInfoObj.LoadXml(keyInfo); cipherDataObj.LoadXml(cipherData); MemoryStream? toDecrypt = null; Stream? decryptedContent = null; StreamReader? streamReader = null; try { toDecrypt = new MemoryStream(cipherDataObj.CipherValue!); decryptedContent = _relDecryptor!.Decrypt(encryptionMethodObj, keyInfoObj, toDecrypt); if ((decryptedContent == null) || (decryptedContent.Length == 0)) throw new CryptographicException(SR.Cryptography_Xml_XrmlUnableToDecryptGrant); streamReader = new StreamReader(decryptedContent); string clearContent = streamReader.ReadToEnd(); // red flag encryptedGrantList[i]!.ParentNode!.InnerXml = clearContent; } finally { toDecrypt?.Close(); decryptedContent?.Close(); streamReader?.Close(); } } } } // License transform has no inner XML elements protected override XmlNodeList? GetInnerXml() { return null; } public override object GetOutput() { return _license!; } public override object GetOutput(Type type) { if ((type != typeof(XmlDocument)) && (!type.IsSubclassOf(typeof(XmlDocument)))) throw new ArgumentException(SR.Cryptography_Xml_TransformIncorrectInputType, nameof(type)); return GetOutput(); } internal override void ClearState() { _license = null; _namespaceManager = null; } // License transform has no inner XML elements public override void LoadInnerXml(XmlNodeList nodeList) { if (nodeList != null && nodeList.Count > 0) throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform); } public override void LoadInput(object obj) { // Check if the Context property is set before this transform is invoked. if (Context == null) throw new CryptographicException(SR.Cryptography_Xml_XrmlMissingContext); _license = new XmlDocument(); _license.PreserveWhitespace = true; _namespaceManager = new XmlNamespaceManager(_license.NameTable); _namespaceManager.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl); _namespaceManager.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl); _namespaceManager.AddNamespace("r", Consts.NamespaceUriCore); XmlElement? currentIssuerContext; XmlElement? currentLicenseContext; XmlNode? signatureNode; // Get the nearest issuer node currentIssuerContext = Context.SelectSingleNode("ancestor-or-self::r:issuer[1]", _namespaceManager) as XmlElement; if (currentIssuerContext == null) throw new CryptographicException(SR.Cryptography_Xml_XrmlMissingIssuer); signatureNode = currentIssuerContext.SelectSingleNode("descendant-or-self::dsig:Signature[1]", _namespaceManager) as XmlElement; signatureNode?.ParentNode!.RemoveChild(signatureNode); // Get the nearest license node currentLicenseContext = currentIssuerContext.SelectSingleNode("ancestor-or-self::r:license[1]", _namespaceManager) as XmlElement; if (currentLicenseContext == null) throw new CryptographicException(SR.Cryptography_Xml_XrmlMissingLicence); XmlNodeList issuerList = currentLicenseContext.SelectNodes("descendant-or-self::r:license[1]/r:issuer", _namespaceManager)!; // Remove all issuer nodes except current for (int i = 0, count = issuerList.Count; i < count; i++) { if (issuerList[i]! == currentIssuerContext) continue; if ((issuerList[i]!.LocalName == Consts.ElementIssuer) && (issuerList[i]!.NamespaceURI == Consts.NamespaceUriCore)) issuerList[i]!.ParentNode!.RemoveChild(issuerList[i]!); } XmlNodeList encryptedGrantList = currentLicenseContext.SelectNodes("/r:license/r:grant/r:encryptedGrant", _namespaceManager)!; if (encryptedGrantList.Count > 0) { if (_relDecryptor == null) throw new CryptographicException(SR.Cryptography_Xml_XrmlMissingIRelDecryptor); DecryptEncryptedGrants(encryptedGrantList); } _license.InnerXml = currentLicenseContext.OuterXml; } } }