RegistryPolicyResolverTests.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. // Copyright (c) .NET Foundation. All rights reserved.
  2. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Security.Cryptography;
  8. using System.Xml.Linq;
  9. using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
  10. using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
  11. using Microsoft.AspNetCore.DataProtection.KeyManagement;
  12. using Microsoft.AspNetCore.Testing.xunit;
  13. using Microsoft.Extensions.DependencyInjection;
  14. using Microsoft.Extensions.DependencyInjection.Extensions;
  15. using Microsoft.Extensions.Options;
  16. using Microsoft.Win32;
  17. using Xunit;
  18. namespace Microsoft.AspNetCore.DataProtection
  19. {
  20. public class RegistryPolicyResolverTests
  21. {
  22. [ConditionalFact]
  23. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  24. public void ResolvePolicy_NoEntries_ResultsInNoPolicies()
  25. {
  26. IServiceCollection serviceCollection = new ServiceCollection();
  27. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  28. {
  29. ["unused"] = 42
  30. });
  31. Assert.Empty(serviceCollection);
  32. }
  33. [ConditionalFact]
  34. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  35. public void ResolvePolicy_KeyEscrowSinks()
  36. {
  37. IServiceCollection serviceCollection = new ServiceCollection();
  38. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  39. {
  40. ["KeyEscrowSinks"] = String.Join(" ;; ; ", new Type[] { typeof(MyKeyEscrowSink1), typeof(MyKeyEscrowSink2) }.Select(t => t.AssemblyQualifiedName))
  41. });
  42. var services = serviceCollection.BuildServiceProvider();
  43. var actualKeyEscrowSinks = services.GetService<IEnumerable<IKeyEscrowSink>>().ToArray();
  44. Assert.Equal(2, actualKeyEscrowSinks.Length);
  45. Assert.IsType(typeof(MyKeyEscrowSink1), actualKeyEscrowSinks[0]);
  46. Assert.IsType(typeof(MyKeyEscrowSink2), actualKeyEscrowSinks[1]);
  47. }
  48. [ConditionalFact]
  49. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  50. public void ResolvePolicy_DefaultKeyLifetime()
  51. {
  52. IServiceCollection serviceCollection = new ServiceCollection();
  53. serviceCollection.AddOptions();
  54. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  55. {
  56. ["DefaultKeyLifetime"] = 1024 // days
  57. });
  58. var services = serviceCollection.BuildServiceProvider();
  59. var keyManagementOptions = services.GetService<IOptions<KeyManagementOptions>>();
  60. Assert.Equal(TimeSpan.FromDays(1024), keyManagementOptions.Value.NewKeyLifetime);
  61. }
  62. [ConditionalFact]
  63. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  64. public void ResolvePolicy_CngCbcEncryption_WithoutExplicitSettings()
  65. {
  66. IServiceCollection serviceCollection = new ServiceCollection();
  67. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  68. {
  69. ["EncryptionType"] = "cng-cbc"
  70. });
  71. var services = serviceCollection.BuildServiceProvider();
  72. var expectedConfiguration = new CngCbcAuthenticatedEncryptorConfiguration(new CngCbcAuthenticatedEncryptionSettings());
  73. var actualConfiguration = (CngCbcAuthenticatedEncryptorConfiguration)services.GetService<IAuthenticatedEncryptorConfiguration>();
  74. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithm, actualConfiguration.Settings.EncryptionAlgorithm);
  75. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
  76. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmProvider, actualConfiguration.Settings.EncryptionAlgorithmProvider);
  77. Assert.Equal(expectedConfiguration.Settings.HashAlgorithm, actualConfiguration.Settings.HashAlgorithm);
  78. Assert.Equal(expectedConfiguration.Settings.HashAlgorithmProvider, actualConfiguration.Settings.HashAlgorithmProvider);
  79. }
  80. [ConditionalFact]
  81. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  82. public void ResolvePolicy_CngCbcEncryption_WithExplicitSettings()
  83. {
  84. IServiceCollection serviceCollection = new ServiceCollection();
  85. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  86. {
  87. ["EncryptionType"] = "cng-cbc",
  88. ["EncryptionAlgorithm"] = "enc-alg",
  89. ["EncryptionAlgorithmKeySize"] = 2048,
  90. ["EncryptionAlgorithmProvider"] = "my-enc-alg-provider",
  91. ["HashAlgorithm"] = "hash-alg",
  92. ["HashAlgorithmProvider"] = "my-hash-alg-provider"
  93. });
  94. var services = serviceCollection.BuildServiceProvider();
  95. var expectedConfiguration = new CngCbcAuthenticatedEncryptorConfiguration(new CngCbcAuthenticatedEncryptionSettings()
  96. {
  97. EncryptionAlgorithm = "enc-alg",
  98. EncryptionAlgorithmKeySize = 2048,
  99. EncryptionAlgorithmProvider = "my-enc-alg-provider",
  100. HashAlgorithm = "hash-alg",
  101. HashAlgorithmProvider = "my-hash-alg-provider"
  102. });
  103. var actualConfiguration = (CngCbcAuthenticatedEncryptorConfiguration)services.GetService<IAuthenticatedEncryptorConfiguration>();
  104. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithm, actualConfiguration.Settings.EncryptionAlgorithm);
  105. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
  106. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmProvider, actualConfiguration.Settings.EncryptionAlgorithmProvider);
  107. Assert.Equal(expectedConfiguration.Settings.HashAlgorithm, actualConfiguration.Settings.HashAlgorithm);
  108. Assert.Equal(expectedConfiguration.Settings.HashAlgorithmProvider, actualConfiguration.Settings.HashAlgorithmProvider);
  109. }
  110. [ConditionalFact]
  111. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  112. public void ResolvePolicy_CngGcmEncryption_WithoutExplicitSettings()
  113. {
  114. IServiceCollection serviceCollection = new ServiceCollection();
  115. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  116. {
  117. ["EncryptionType"] = "cng-gcm"
  118. });
  119. var services = serviceCollection.BuildServiceProvider();
  120. var expectedConfiguration = new CngGcmAuthenticatedEncryptorConfiguration(new CngGcmAuthenticatedEncryptionSettings());
  121. var actualConfiguration = (CngGcmAuthenticatedEncryptorConfiguration)services.GetService<IAuthenticatedEncryptorConfiguration>();
  122. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithm, actualConfiguration.Settings.EncryptionAlgorithm);
  123. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
  124. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmProvider, actualConfiguration.Settings.EncryptionAlgorithmProvider);
  125. }
  126. [ConditionalFact]
  127. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  128. public void ResolvePolicy_CngGcmEncryption_WithExplicitSettings()
  129. {
  130. IServiceCollection serviceCollection = new ServiceCollection();
  131. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  132. {
  133. ["EncryptionType"] = "cng-gcm",
  134. ["EncryptionAlgorithm"] = "enc-alg",
  135. ["EncryptionAlgorithmKeySize"] = 2048,
  136. ["EncryptionAlgorithmProvider"] = "my-enc-alg-provider"
  137. });
  138. var services = serviceCollection.BuildServiceProvider();
  139. var expectedConfiguration = new CngGcmAuthenticatedEncryptorConfiguration(new CngGcmAuthenticatedEncryptionSettings()
  140. {
  141. EncryptionAlgorithm = "enc-alg",
  142. EncryptionAlgorithmKeySize = 2048,
  143. EncryptionAlgorithmProvider = "my-enc-alg-provider"
  144. });
  145. var actualConfiguration = (CngGcmAuthenticatedEncryptorConfiguration)services.GetService<IAuthenticatedEncryptorConfiguration>();
  146. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithm, actualConfiguration.Settings.EncryptionAlgorithm);
  147. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
  148. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmProvider, actualConfiguration.Settings.EncryptionAlgorithmProvider);
  149. }
  150. [ConditionalFact]
  151. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  152. public void ResolvePolicy_ManagedEncryption_WithoutExplicitSettings()
  153. {
  154. IServiceCollection serviceCollection = new ServiceCollection();
  155. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  156. {
  157. ["EncryptionType"] = "managed"
  158. });
  159. var services = serviceCollection.BuildServiceProvider();
  160. var expectedConfiguration = new ManagedAuthenticatedEncryptorConfiguration(new ManagedAuthenticatedEncryptionSettings());
  161. var actualConfiguration = (ManagedAuthenticatedEncryptorConfiguration)services.GetService<IAuthenticatedEncryptorConfiguration>();
  162. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmType, actualConfiguration.Settings.EncryptionAlgorithmType);
  163. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
  164. Assert.Equal(expectedConfiguration.Settings.ValidationAlgorithmType, actualConfiguration.Settings.ValidationAlgorithmType);
  165. }
  166. [ConditionalFact]
  167. [ConditionalRunTestOnlyIfHkcuRegistryAvailable]
  168. public void ResolvePolicy_ManagedEncryption_WithExplicitSettings()
  169. {
  170. IServiceCollection serviceCollection = new ServiceCollection();
  171. RunTestWithRegValues(serviceCollection, new Dictionary<string, object>()
  172. {
  173. ["EncryptionType"] = "managed",
  174. ["EncryptionAlgorithmType"] = typeof(TripleDES).AssemblyQualifiedName,
  175. ["EncryptionAlgorithmKeySize"] = 2048,
  176. ["ValidationAlgorithmType"] = typeof(HMACSHA1).AssemblyQualifiedName
  177. });
  178. var services = serviceCollection.BuildServiceProvider();
  179. var expectedConfiguration = new ManagedAuthenticatedEncryptorConfiguration(new ManagedAuthenticatedEncryptionSettings()
  180. {
  181. EncryptionAlgorithmType = typeof(TripleDES),
  182. EncryptionAlgorithmKeySize = 2048,
  183. ValidationAlgorithmType = typeof(HMACSHA1)
  184. });
  185. var actualConfiguration = (ManagedAuthenticatedEncryptorConfiguration)services.GetService<IAuthenticatedEncryptorConfiguration>();
  186. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmType, actualConfiguration.Settings.EncryptionAlgorithmType);
  187. Assert.Equal(expectedConfiguration.Settings.EncryptionAlgorithmKeySize, actualConfiguration.Settings.EncryptionAlgorithmKeySize);
  188. Assert.Equal(expectedConfiguration.Settings.ValidationAlgorithmType, actualConfiguration.Settings.ValidationAlgorithmType);
  189. }
  190. private static void RunTestWithRegValues(IServiceCollection services, Dictionary<string, object> regValues)
  191. {
  192. WithUniqueTempRegKey(registryKey =>
  193. {
  194. foreach (var entry in regValues)
  195. {
  196. registryKey.SetValue(entry.Key, entry.Value);
  197. }
  198. var policyResolver = new RegistryPolicyResolver(registryKey);
  199. services.Add(policyResolver.ResolvePolicy());
  200. });
  201. }
  202. /// <summary>
  203. /// Runs a test and cleans up the registry key afterward.
  204. /// </summary>
  205. private static void WithUniqueTempRegKey(Action<RegistryKey> testCode)
  206. {
  207. string uniqueName = Guid.NewGuid().ToString();
  208. var uniqueSubkey = LazyHkcuTempKey.Value.CreateSubKey(uniqueName);
  209. try
  210. {
  211. testCode(uniqueSubkey);
  212. }
  213. finally
  214. {
  215. // clean up when test is done
  216. LazyHkcuTempKey.Value.DeleteSubKeyTree(uniqueName, throwOnMissingSubKey: false);
  217. }
  218. }
  219. private static readonly Lazy<RegistryKey> LazyHkcuTempKey = new Lazy<RegistryKey>(() =>
  220. {
  221. try
  222. {
  223. return Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\ASP.NET\temp");
  224. }
  225. catch
  226. {
  227. // swallow all failures
  228. return null;
  229. }
  230. });
  231. private class ConditionalRunTestOnlyIfHkcuRegistryAvailable : Attribute, ITestCondition
  232. {
  233. public bool IsMet => (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && LazyHkcuTempKey.Value != null);
  234. public string SkipReason { get; } = "HKCU registry couldn't be opened.";
  235. }
  236. private class MyKeyEscrowSink1 : IKeyEscrowSink
  237. {
  238. public void Store(Guid keyId, XElement element)
  239. {
  240. throw new NotImplementedException();
  241. }
  242. }
  243. private class MyKeyEscrowSink2 : IKeyEscrowSink
  244. {
  245. public void Store(Guid keyId, XElement element)
  246. {
  247. throw new NotImplementedException();
  248. }
  249. }
  250. }
  251. }