Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Wicher <mordotymoja@gmail.com>2017-04-05 22:48:58 +0300
committerJeremy Barton <jbarton@microsoft.com>2017-04-05 22:48:58 +0300
commit8a61763fcc683c64d21db2dd8d62170557c4ba37 (patch)
treee434701b6f14c3b664b8a8944a24cee9684b3ce4 /src/System.Security.Cryptography.Xml
parent7ed2b62dcd1ea79f03be973d2d4349390fcef829 (diff)
Add XmlLicenseTransform E2E test (urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform) (#17953)
Diffstat (limited to 'src/System.Security.Cryptography.Xml')
-rw-r--r--src/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj1
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs213
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs175
3 files changed, 387 insertions, 2 deletions
diff --git a/src/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj b/src/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj
index eabccb5b52..488e674c5d 100644
--- a/src/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj
+++ b/src/System.Security.Cryptography.Xml/tests/System.Security.Cryptography.Xml.Tests.csproj
@@ -49,6 +49,7 @@
<Compile Include="XmlDsigExcC14NWithCommentsTransformTest.cs" />
<Compile Include="XmlDsigXPathTransformTest.cs" />
<Compile Include="XmlDsigXsltTransformTest.cs" />
+ <Compile Include="XmlLicenseEncryptedRef.cs" />
<Compile Include="XmlLicenseTransformTest.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs b/src/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs
new file mode 100644
index 0000000000..e1e0b75df1
--- /dev/null
+++ b/src/System.Security.Cryptography.Xml/tests/XmlLicenseEncryptedRef.cs
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Security.Cryptography.Xml.Tests
+{
+ public class XmlLicenseEncryptedRef : IRelDecryptor
+ {
+ List<AsymmetricAlgorithm> _asymmetricKeys = new List<AsymmetricAlgorithm>();
+
+ public XmlLicenseEncryptedRef()
+ {
+ }
+
+ public void AddAsymmetricKey(AsymmetricAlgorithm key)
+ {
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+
+ _asymmetricKeys.Add(key);
+ }
+
+ private static bool PublicKeysEqual(RSAParameters a, RSAParameters b)
+ {
+ return a.Exponent.SequenceEqual(b.Exponent) && a.Modulus.SequenceEqual(b.Modulus);
+ }
+
+ public Stream Decrypt(EncryptionMethod encryptionMethod, KeyInfo keyInfo, Stream toDecrypt)
+ {
+ Assert.NotNull(encryptionMethod);
+ Assert.NotNull(keyInfo);
+ Assert.NotNull(toDecrypt);
+ Assert.True(encryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncAES128Url
+ || encryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncAES192Url
+ || encryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncAES256Url);
+
+ Assert.Equal(keyInfo.Count, 1);
+
+ byte[] decryptedKey = null;
+
+ foreach (KeyInfoClause clause in keyInfo)
+ {
+ if (clause is KeyInfoEncryptedKey)
+ {
+ KeyInfoEncryptedKey encryptedKeyInfo = clause as KeyInfoEncryptedKey;
+ EncryptedKey encryptedKey = encryptedKeyInfo.EncryptedKey;
+
+ Assert.Equal(encryptedKey.EncryptionMethod.KeyAlgorithm, EncryptedXml.XmlEncRSAOAEPUrl);
+ Assert.Equal(encryptedKey.KeyInfo.Count, 1);
+ Assert.NotEqual(_asymmetricKeys.Count, 0);
+
+ RSAParameters rsaParams = new RSAParameters();
+ RSAParameters rsaInputParams = new RSAParameters();
+
+ foreach (KeyInfoClause rsa in encryptedKey.KeyInfo)
+ {
+ if (rsa is RSAKeyValue)
+ {
+ rsaParams = (rsa as RSAKeyValue).Key.ExportParameters(false);
+ break;
+ }
+ else
+ {
+ Assert.True(false, "Invalid License - MalformedKeyInfoClause");
+ }
+ }
+
+ bool keyMismatch = true;
+ foreach (AsymmetricAlgorithm key in _asymmetricKeys)
+ {
+ RSA rsaKey = key as RSA;
+ Assert.NotNull(rsaKey);
+
+ rsaInputParams = rsaKey.ExportParameters(false);
+
+ if (!PublicKeysEqual(rsaParams, rsaInputParams))
+ {
+ continue;
+ }
+
+ keyMismatch = false;
+
+ // Decrypt session key
+ byte[] encryptedKeyValue = encryptedKey.CipherData.CipherValue;
+
+ if (encryptedKeyValue == null)
+ throw new CryptographicException("MissingKeyCipher");
+
+ decryptedKey = EncryptedXml.DecryptKey(encryptedKeyValue,
+ rsaKey, true);
+ break;
+ }
+
+ if (keyMismatch)
+ {
+ throw new Exception("Invalid License - AsymmetricKeyMismatch");
+ }
+ }
+ else if (clause is KeyInfoName)
+ {
+ Assert.True(false, "This test should not have KeyInfoName clauses");
+ }
+ else
+ {
+ throw new CryptographicException("MalformedKeyInfoClause");
+ }
+
+ break;
+ }
+
+ if (decryptedKey == null)
+ {
+ throw new CryptographicException("KeyDecryptionFailure");
+ }
+
+ using (Aes aes = Aes.Create())
+ {
+ aes.Key = decryptedKey;
+ aes.Padding = PaddingMode.PKCS7;
+ aes.Mode = CipherMode.CBC;
+ return DecryptStream(toDecrypt, aes);
+ }
+ }
+
+ private static Stream DecryptStream(Stream toDecrypt, SymmetricAlgorithm alg)
+ {
+ Assert.NotNull(alg);
+
+ byte[] IV = new byte[alg.BlockSize / 8];
+
+ // Get the IV from the encrypted content.
+ toDecrypt.Read(IV, 0, IV.Length);
+ byte[] encryptedContentValue = new byte[toDecrypt.Length - IV.Length];
+
+ // Get the encrypted content following the IV.
+ toDecrypt.Read(encryptedContentValue, 0, encryptedContentValue.Length);
+
+ var msDecrypt = new MemoryStream();
+
+ using (ICryptoTransform decryptor = alg.CreateDecryptor(alg.Key, IV))
+ using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write, leaveOpen: true))
+ {
+ csDecrypt.Write(encryptedContentValue, 0, encryptedContentValue.Length);
+ }
+
+ msDecrypt.Position = 0;
+ return msDecrypt;
+ }
+
+ public static void Encrypt(Stream toEncrypt, RSA key, out KeyInfo keyInfo, out EncryptionMethod encryptionMethod, out CipherData cipherData)
+ {
+ using (Aes sessionKey = Aes.Create())
+ {
+ sessionKey.KeySize = 128;
+ encryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES128Url);
+ keyInfo = new KeyInfo();
+
+ EncryptedKey encKey;
+ keyInfo.AddClause(
+ new KeyInfoEncryptedKey(
+ encKey = new EncryptedKey()
+ {
+ CipherData = new CipherData(EncryptedXml.EncryptKey(sessionKey.Key, key, useOAEP: true)),
+ EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSAOAEPUrl)
+ }));
+
+ encKey.KeyInfo.AddClause(new RSAKeyValue(key));
+
+ byte[] dataToEncrypt = new byte[toEncrypt.Length];
+ toEncrypt.Read(dataToEncrypt, 0, (int)toEncrypt.Length);
+
+ var encryptedXml = new EncryptedXml();
+ encryptedXml.Padding = PaddingMode.PKCS7;
+ encryptedXml.Mode = CipherMode.CBC;
+ byte[] encryptedData = encryptedXml.EncryptData(dataToEncrypt, sessionKey);
+ cipherData = new CipherData(encryptedData);
+ }
+ }
+
+ [Fact]
+ public static void ItRoundTrips()
+ {
+ byte[] input = new byte[] { 1, 2, 7, 4 };
+ MemoryStream ms = new MemoryStream(input);
+ KeyInfo keyInfo;
+ EncryptionMethod encMethod;
+ CipherData cipherData;
+ using (RSA rsa = RSA.Create())
+ {
+ Encrypt(ms, rsa, out keyInfo, out encMethod, out cipherData);
+
+ XmlLicenseEncryptedRef decr = new XmlLicenseEncryptedRef();
+ decr.AddAsymmetricKey(rsa);
+ using (var encrypted = new MemoryStream(cipherData.CipherValue))
+ using (Stream decrypted = decr.Decrypt(encMethod, keyInfo, encrypted))
+ {
+ byte[] decryptedBytes = new byte[decrypted.Length];
+ decrypted.Read(decryptedBytes, 0, (int)decrypted.Length);
+ Assert.Equal(input, decryptedBytes);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs
index e5aeed2560..9fdca09a8c 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs
@@ -46,6 +46,8 @@ namespace System.Security.Cryptography.Xml.Tests
public class XmlLicenseTransformTest
{
+ public const string LicenseTransformNsUrl = "urn:mpeg:mpeg21:2003:01-REL-R-NS";
+ public const string LicenseTransformUrl = LicenseTransformNsUrl + ":licenseTransform";
private UnprotectedXmlLicenseTransform transform;
public XmlLicenseTransformTest()
@@ -56,8 +58,7 @@ namespace System.Security.Cryptography.Xml.Tests
[Fact] // ctor ()
public void Constructor1()
{
- Assert.Equal("urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform",
- transform.Algorithm);
+ Assert.Equal(LicenseTransformUrl, transform.Algorithm);
Assert.Null(transform.Decryptor);
Type[] input = transform.InputTypes;
@@ -155,6 +156,39 @@ namespace System.Security.Cryptography.Xml.Tests
{
Assert.Throws<ArgumentException>(() => transform.GetOutput(typeof(string)));
}
+
+ [Fact]
+ public static void ItDecryptsLicense()
+ {
+ using (var key = RSA.Create())
+ {
+ string expected;
+ string encryptedLicenseWithGrants = GenerateLicenseXmlWithEncryptedGrants(key, out expected);
+
+ Assert.Contains("hello", expected);
+ Assert.DoesNotContain("hello", encryptedLicenseWithGrants);
+
+ XmlNamespaceManager nsManager;
+ XmlDocument toDecrypt = LoadXmlWithLicenseNs(encryptedLicenseWithGrants, out nsManager);
+
+ var decryptor = new XmlLicenseEncryptedRef();
+ var transform = new XmlLicenseTransform()
+ {
+ Decryptor = decryptor,
+ Context = FindLicenseTransformContext(toDecrypt, nsManager)
+ };
+
+ decryptor.AddAsymmetricKey(key);
+
+ // Context is the input for this transform, argument is always ignored
+ transform.LoadInput(null);
+
+ XmlDocument decryptedDoc = transform.GetOutput() as XmlDocument;
+ Assert.NotNull(decryptedDoc);
+ string decrypted = decryptedDoc.OuterXml;
+ Assert.Equal(expected, decrypted);
+ }
+ }
private XmlDocument GetDocumentFromResource(string resourceName)
{
@@ -168,6 +202,143 @@ namespace System.Security.Cryptography.Xml.Tests
return doc;
}
+
+ private static string GenerateLicenseXmlWithEncryptedGrants(RSA key, out string plainTextLicense)
+ {
+ plainTextLicense = @"<r:license xmlns:r=""urn:mpeg:mpeg21:2003:01-REL-R-NS"">
+ <r:title>Test License</r:title>
+ <r:grant>
+ <r:forAll varName=""licensor"" />
+ <r:forAll varName=""property"" />
+ <r:forAll varName=""p0"">
+ <r:propertyPossessor>
+ <r:propertyAbstract varRef=""property"" />
+ </r:propertyPossessor>
+ </r:forAll>
+ <r:keyHolder varRef=""licensor"" />
+ <r:issue />
+ <r:grant>
+ <r:principal varRef=""p0"" />
+ <x:bar xmlns:x=""urn:foo"" />
+ <r:digitalResource>
+ <testItem>hello</testItem>
+ </r:digitalResource>
+ <renderer xmlns=""urn:mpeg:mpeg21:2003:01-REL-MX-NS"">
+ <mx:wildcard xmlns:mx=""urn:mpeg:mpeg21:2003:01-REL-MX-NS"">
+ <r:anXmlExpression>some-xpath-expression</r:anXmlExpression>
+ </mx:wildcard>
+ <mx:wildcard xmlns:mx=""urn:mpeg:mpeg21:2003:01-REL-MX-NS"">
+ <r:anXmlExpression>some-other-xpath-expression</r:anXmlExpression>
+ </mx:wildcard>
+ </renderer>
+ </r:grant>
+ <validityIntervalFloating xmlns=""urn:mpeg:mpeg21:2003:01-REL-SX-NS"">
+ <sx:duration xmlns:sx=""urn:mpeg:mpeg21:2003:01-REL-SX-NS"">P2D</sx:duration>
+ </validityIntervalFloating>
+ </r:grant>
+ <r:grant>
+ <r:possessProperty />
+ <emailName xmlns=""urn:mpeg:mpeg21:2003:01-REL-SX-NS"">test@test</emailName>
+ </r:grant>
+ <r:issuer xmlns:r=""urn:mpeg:mpeg21:2003:01-REL-R-NS"">
+ <r:details>
+ <r:timeOfIssue>2099-11-11T11:11:11Z</r:timeOfIssue>
+ </r:details>
+ </r:issuer>
+</r:license>".Replace("\r\n", "\n");
+
+ XmlNamespaceManager nsManager;
+ XmlDocument doc = LoadXmlWithLicenseNs(plainTextLicense, out nsManager);
+
+ EncryptLicense(FindLicenseTransformContext(doc, nsManager), key);
+
+ return doc.OuterXml;
+ }
+
+ private static XmlElement FindLicenseTransformContext(XmlDocument doc, XmlNamespaceManager nsManager)
+ {
+ XmlNodeList issuerList = doc.SelectNodes("//r:issuer", nsManager);
+ return issuerList[0] as XmlElement;
+ }
+
+ private static XmlDocument LoadXmlWithLicenseNs(string xml, out XmlNamespaceManager nsManager)
+ {
+ XmlDocument doc = new XmlDocument();
+ doc.PreserveWhitespace = true;
+ nsManager = new XmlNamespaceManager(doc.NameTable);
+ nsManager.AddNamespace("r", LicenseTransformNsUrl);
+ doc.LoadXml(xml);
+ return doc;
+ }
+
+ private static void EncryptGrant(XmlNode grant, RSA key, XmlNamespaceManager nsMgr)
+ {
+ using (var ms = new MemoryStream())
+ using (var sw = new StreamWriter(ms))
+ {
+ sw.Write(grant.InnerXml);
+ sw.Flush();
+ ms.Position = 0;
+
+ KeyInfo keyInfo;
+ EncryptionMethod encryptionMethod;
+ CipherData cipherData;
+ XmlLicenseEncryptedRef.Encrypt(ms, key, out keyInfo, out encryptionMethod, out cipherData);
+ grant.RemoveAll();
+ XmlDocument doc = grant.OwnerDocument;
+ XmlElement encryptedGrant = doc.CreateElement("encryptedGrant", LicenseTransformNsUrl);
+ grant.AppendChild(encryptedGrant);
+
+ encryptedGrant.AppendChild(doc.ImportNode(keyInfo.GetXml(), true));
+ encryptedGrant.AppendChild(doc.ImportNode(encryptionMethod.GetXml(), true));
+ encryptedGrant.AppendChild(doc.ImportNode(cipherData.GetXml(), true));
+ }
+ }
+
+ private static void EncryptLicense(XmlElement context, RSA key)
+ {
+ XmlDocument doc = context.OwnerDocument;
+
+ var nsMgr = new XmlNamespaceManager(doc.NameTable);
+ nsMgr.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
+ nsMgr.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
+ nsMgr.AddNamespace("r", LicenseTransformNsUrl);
+
+ XmlElement currentIssuerContext = context.SelectSingleNode("ancestor-or-self::r:issuer[1]", nsMgr) as XmlElement;
+ Assert.NotEqual(currentIssuerContext, null);
+
+ XmlElement signatureNode = currentIssuerContext.SelectSingleNode("descendant-or-self::dsig:Signature[1]", nsMgr) as XmlElement;
+ if (signatureNode != null)
+ {
+ signatureNode.ParentNode.RemoveChild(signatureNode);
+ }
+
+ XmlElement currentLicenseContext = currentIssuerContext.SelectSingleNode("ancestor-or-self::r:license[1]", nsMgr) as XmlElement;
+ Assert.NotEqual(currentLicenseContext, null);
+
+ XmlNodeList issuerList = currentLicenseContext.SelectNodes("descendant-or-self::r:license[1]/r:issuer", nsMgr);
+ for (int i = 0; i < issuerList.Count; i++)
+ {
+ XmlNode issuer = issuerList[i];
+ if (issuer == currentIssuerContext)
+ {
+ continue;
+ }
+
+ if (issuer.LocalName == "issuer"
+ && issuer.NamespaceURI == LicenseTransformNsUrl)
+ {
+ issuer.ParentNode.RemoveChild(issuer);
+ }
+ }
+
+ XmlNodeList encryptedGrantList = currentLicenseContext.SelectNodes("/r:license/r:grant", nsMgr);
+
+ for (int i = 0; i < encryptedGrantList.Count; i++)
+ {
+ EncryptGrant(encryptedGrantList[i], key, nsMgr);
+ }
+ }
}
}