PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System.Core/Microsoft/Win32/SafeHandles/CapiSafeHandles.cs

https://github.com/pruiz/mono
C# | 426 lines | 321 code | 47 blank | 58 comment | 30 complexity | 414a978fde28406abe779237aee1e07d MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. // ==++==
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // ==--==
  6. using System;
  7. using System.Diagnostics;
  8. using System.Runtime.CompilerServices;
  9. using System.Runtime.ConstrainedExecution;
  10. using System.Runtime.InteropServices;
  11. using System.Security;
  12. using System.Security.Cryptography;
  13. using System.Diagnostics.CodeAnalysis;
  14. using System.Diagnostics.Contracts;
  15. namespace Microsoft.Win32.SafeHandles {
  16. /// <summary>
  17. /// SafeHandle for buffers returned by the Axl APIs
  18. /// </summary>
  19. #if !FEATURE_CORESYSTEM
  20. #pragma warning disable 618 // Have not migrated to v4 transparency yet
  21. [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
  22. #pragma warning restore 618
  23. #endif
  24. internal sealed class SafeAxlBufferHandle : SafeHandleZeroOrMinusOneIsInvalid {
  25. private SafeAxlBufferHandle() : base(true) {
  26. return;
  27. }
  28. [DllImport("kernel32")]
  29. #if !FEATURE_CORESYSTEM
  30. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  31. #endif
  32. [SuppressUnmanagedCodeSecurity]
  33. private static extern IntPtr GetProcessHeap();
  34. [DllImport("kernel32")]
  35. #if !FEATURE_CORESYSTEM
  36. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  37. #endif
  38. [SuppressUnmanagedCodeSecurity]
  39. [return: MarshalAs(UnmanagedType.Bool)]
  40. private static extern bool HeapFree(IntPtr hHeap, int dwFlags, IntPtr lpMem);
  41. protected override bool ReleaseHandle() {
  42. // _AxlFree is a wrapper around HeapFree on the process heap. Since it is not exported from mscorwks
  43. // we just call HeapFree directly. This needs to be updated if _AxlFree is ever changed.
  44. HeapFree(GetProcessHeap(), 0, handle);
  45. return true;
  46. }
  47. }
  48. /// <summary>
  49. /// SafeHandle base class for CAPI handles (such as HCRYPTKEY and HCRYPTHASH) which must keep their
  50. /// CSP alive as long as they stay alive as well. CAPI requires that all child handles belonging to a
  51. /// HCRYPTPROV must be destroyed up before the reference count to the HCRYPTPROV drops to zero.
  52. /// Since we cannot control the order of finalization between the two safe handles, SafeCapiHandleBase
  53. /// maintains a native refcount on its parent HCRYPTPROV to ensure that if the corresponding
  54. /// SafeCspKeyHandle is finalized first CAPI still keeps the provider alive.
  55. /// </summary>
  56. #if FEATURE_CORESYSTEM
  57. [System.Security.SecurityCritical]
  58. #else
  59. #pragma warning disable 618 // Have not migrated to v4 transparency yet
  60. [SecurityCritical(SecurityCriticalScope.Everything)]
  61. #pragma warning restore 618
  62. #endif
  63. internal abstract class SafeCapiHandleBase : SafeHandleZeroOrMinusOneIsInvalid {
  64. private IntPtr m_csp;
  65. #if FEATURE_CORESYSTEM
  66. [System.Security.SecurityCritical]
  67. #endif
  68. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  69. internal SafeCapiHandleBase() : base(true) {
  70. }
  71. #if FEATURE_CORESYSTEM
  72. [System.Security.SecurityCritical]
  73. #endif
  74. [DllImport("advapi32", SetLastError = true)]
  75. #if !FEATURE_CORESYSTEM
  76. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  77. #endif
  78. [SuppressUnmanagedCodeSecurity]
  79. [return: MarshalAs(UnmanagedType.Bool)]
  80. private static extern bool CryptContextAddRef(IntPtr hProv,
  81. IntPtr pdwReserved,
  82. int dwFlags);
  83. #if FEATURE_CORESYSTEM
  84. [System.Security.SecurityCritical]
  85. #endif
  86. [DllImport("advapi32")]
  87. #if !FEATURE_CORESYSTEM
  88. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  89. #endif
  90. [SuppressUnmanagedCodeSecurity]
  91. [return: MarshalAs(UnmanagedType.Bool)]
  92. private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
  93. protected IntPtr ParentCsp {
  94. get { return m_csp; }
  95. #if !FEATURE_CORESYSTEM
  96. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  97. #endif
  98. set {
  99. // We should not be resetting the parent CSP if it's already been set once - that will
  100. // lead to leaking the original handle.
  101. Debug.Assert(m_csp == IntPtr.Zero);
  102. int error = (int)CapiNative.ErrorCode.Success;
  103. // A successful call to CryptContextAddRef and an assignment of the handle value to our field
  104. // SafeHandle need to happen atomically, so we contain them within a CER.
  105. RuntimeHelpers.PrepareConstrainedRegions();
  106. try { }
  107. finally {
  108. if (CryptContextAddRef(value, IntPtr.Zero, 0)) {
  109. m_csp = value;
  110. }
  111. else {
  112. error = Marshal.GetLastWin32Error();
  113. }
  114. }
  115. if (error != (int)CapiNative.ErrorCode.Success) {
  116. throw new CryptographicException(error);
  117. }
  118. }
  119. }
  120. #if FEATURE_CORESYSTEM
  121. [System.Security.SecurityCritical]
  122. #endif
  123. #if !FEATURE_CORESYSTEM
  124. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  125. #endif
  126. internal void SetParentCsp(SafeCspHandle parentCsp) {
  127. bool addedRef = false;
  128. RuntimeHelpers.PrepareConstrainedRegions();
  129. try {
  130. parentCsp.DangerousAddRef(ref addedRef);
  131. IntPtr rawParentHandle = parentCsp.DangerousGetHandle();
  132. ParentCsp = rawParentHandle;
  133. }
  134. finally {
  135. if (addedRef) {
  136. parentCsp.DangerousRelease();
  137. }
  138. }
  139. }
  140. #if FEATURE_CORESYSTEM
  141. [System.Security.SecurityCritical]
  142. #endif
  143. protected abstract bool ReleaseCapiChildHandle();
  144. #if FEATURE_CORESYSTEM
  145. [System.Security.SecurityCritical]
  146. #endif
  147. protected override sealed bool ReleaseHandle() {
  148. // Order is important here - we must destroy the child handle before the parent CSP
  149. bool destroyedChild = ReleaseCapiChildHandle();
  150. bool releasedCsp = true;
  151. if (m_csp != IntPtr.Zero) {
  152. releasedCsp = CryptReleaseContext(m_csp, 0);
  153. }
  154. return destroyedChild && releasedCsp;
  155. }
  156. }
  157. /// <summary>
  158. /// SafeHandle for CAPI hash algorithms (HCRYPTHASH)
  159. /// </summary>
  160. #if FEATURE_CORESYSTEM
  161. [System.Security.SecurityCritical]
  162. #else
  163. #pragma warning disable 618 // Have not migrated to v4 transparency yet
  164. [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
  165. #pragma warning restore 618
  166. #endif
  167. internal sealed class SafeCapiHashHandle : SafeCapiHandleBase {
  168. private static volatile SafeCapiHashHandle s_invalidHandle;
  169. #if FEATURE_CORESYSTEM
  170. [System.Security.SecurityCritical]
  171. #endif
  172. private SafeCapiHashHandle() {
  173. }
  174. /// <summary>
  175. /// NULL hash handle
  176. /// </summary>
  177. public static SafeCapiHashHandle InvalidHandle {
  178. get {
  179. if (s_invalidHandle == null) {
  180. // More than one of these might get created in parallel, but that's okay.
  181. // Saving one to the field saves on GC tracking, but by SuppressingFinalize on
  182. // any instance returned there's already less finalization pressure.
  183. SafeCapiHashHandle handle = new SafeCapiHashHandle();
  184. handle.SetHandle(IntPtr.Zero);
  185. GC.SuppressFinalize(handle);
  186. s_invalidHandle = handle;
  187. }
  188. return s_invalidHandle;
  189. }
  190. }
  191. #if FEATURE_CORESYSTEM
  192. [System.Security.SecurityCritical]
  193. #endif
  194. [DllImport("advapi32")]
  195. #if !FEATURE_CORESYSTEM
  196. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  197. #endif
  198. [SuppressUnmanagedCodeSecurity]
  199. [return: MarshalAs(UnmanagedType.Bool)]
  200. private static extern bool CryptDestroyHash(IntPtr hHash);
  201. #if FEATURE_CORESYSTEM
  202. [System.Security.SecurityCritical]
  203. #endif
  204. protected override bool ReleaseCapiChildHandle() {
  205. return CryptDestroyHash(handle);
  206. }
  207. }
  208. /// <summary>
  209. /// SafeHandle for CAPI keys (HCRYPTKEY)
  210. /// </summary>
  211. #if FEATURE_CORESYSTEM
  212. [System.Security.SecurityCritical]
  213. #else
  214. #pragma warning disable 618 // Have not migrated to v4 transparency yet
  215. [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
  216. #pragma warning restore 618
  217. #endif
  218. internal sealed class SafeCapiKeyHandle : SafeCapiHandleBase {
  219. private static volatile SafeCapiKeyHandle s_invalidHandle;
  220. #if FEATURE_CORESYSTEM
  221. [System.Security.SecurityCritical]
  222. #endif
  223. private SafeCapiKeyHandle() {
  224. }
  225. /// <summary>
  226. /// NULL key handle
  227. /// </summary>
  228. internal static SafeCapiKeyHandle InvalidHandle {
  229. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  230. get {
  231. if (s_invalidHandle == null) {
  232. // More than one of these might get created in parallel, but that's okay.
  233. // Saving one to the field saves on GC tracking, but by SuppressingFinalize on
  234. // any instance returned there's already less finalization pressure.
  235. SafeCapiKeyHandle handle = new SafeCapiKeyHandle();
  236. handle.SetHandle(IntPtr.Zero);
  237. GC.SuppressFinalize(handle);
  238. s_invalidHandle = handle;
  239. }
  240. return s_invalidHandle;
  241. }
  242. }
  243. [DllImport("advapi32")]
  244. #if FEATURE_CORESYSTEM
  245. [System.Security.SecurityCritical]
  246. #else
  247. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  248. #endif
  249. [SuppressUnmanagedCodeSecurity]
  250. [return: MarshalAs(UnmanagedType.Bool)]
  251. private static extern bool CryptDestroyKey(IntPtr hKey);
  252. /// <summary>
  253. /// Make a copy of this key handle
  254. /// </summary>
  255. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  256. #if FEATURE_CORESYSTEM
  257. [System.Security.SecurityCritical]
  258. #endif
  259. internal SafeCapiKeyHandle Duplicate() {
  260. Contract.Requires(!IsInvalid && !IsClosed);
  261. Contract.Ensures(Contract.Result<SafeCapiKeyHandle>() != null && !Contract.Result<SafeCapiKeyHandle>().IsInvalid && !Contract.Result<SafeCapiKeyHandle>().IsClosed);
  262. SafeCapiKeyHandle duplicate = null;
  263. RuntimeHelpers.PrepareConstrainedRegions();
  264. try {
  265. if (!CapiNative.UnsafeNativeMethods.CryptDuplicateKey(this, IntPtr.Zero, 0, out duplicate)) {
  266. throw new CryptographicException(Marshal.GetLastWin32Error());
  267. }
  268. }
  269. finally {
  270. if (duplicate != null && !duplicate.IsInvalid && ParentCsp != IntPtr.Zero) {
  271. duplicate.ParentCsp = ParentCsp;
  272. }
  273. }
  274. return duplicate;
  275. }
  276. #if FEATURE_CORESYSTEM
  277. [System.Security.SecurityCritical]
  278. #endif
  279. protected override bool ReleaseCapiChildHandle() {
  280. return CryptDestroyKey(handle);
  281. }
  282. }
  283. /// <summary>
  284. /// SafeHandle for crypto service providers (HCRYPTPROV)
  285. /// </summary>
  286. #if FEATURE_CORESYSTEM
  287. [System.Security.SecurityCritical]
  288. #else
  289. #pragma warning disable 618 // Have not migrated to v4 transparency yet
  290. [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
  291. #pragma warning restore 618
  292. #endif
  293. internal sealed class SafeCspHandle : SafeHandleZeroOrMinusOneIsInvalid {
  294. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  295. #if FEATURE_CORESYSTEM
  296. [System.Security.SecurityCritical]
  297. #endif
  298. private SafeCspHandle() : base(true) {
  299. return;
  300. }
  301. [DllImport("advapi32", SetLastError = true)]
  302. #if !FEATURE_CORESYSTEM
  303. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  304. #endif
  305. [SuppressUnmanagedCodeSecurity]
  306. #if FEATURE_CORESYSTEM
  307. [System.Security.SecurityCritical]
  308. #endif
  309. [return: MarshalAs(UnmanagedType.Bool)]
  310. private static extern bool CryptContextAddRef(SafeCspHandle hProv,
  311. IntPtr pdwReserved,
  312. int dwFlags);
  313. [DllImport("advapi32")]
  314. #if !FEATURE_CORESYSTEM
  315. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  316. #endif
  317. [SuppressUnmanagedCodeSecurity]
  318. #if FEATURE_CORESYSTEM
  319. [System.Security.SecurityCritical]
  320. #endif
  321. [return: MarshalAs(UnmanagedType.Bool)]
  322. private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
  323. /// <summary>
  324. /// Create a second SafeCspHandle which refers to the same HCRYPTPROV
  325. /// </summary>
  326. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  327. #if FEATURE_CORESYSTEM
  328. [System.Security.SecurityCritical]
  329. #endif
  330. public SafeCspHandle Duplicate() {
  331. Contract.Requires(!IsInvalid && !IsClosed);
  332. // In the window between the call to CryptContextAddRef and when the raw handle value is assigned
  333. // into this safe handle, there's a second reference to the original safe handle that the CLR does
  334. // not know about, so we need to bump the reference count around this entire operation to ensure
  335. // that we don't have the original handle closed underneath us.
  336. bool acquired = false;
  337. RuntimeHelpers.PrepareConstrainedRegions();
  338. try {
  339. DangerousAddRef(ref acquired);
  340. IntPtr originalHandle = DangerousGetHandle();
  341. int error = (int)CapiNative.ErrorCode.Success;
  342. SafeCspHandle duplicate = new SafeCspHandle();
  343. // A successful call to CryptContextAddRef and an assignment of the handle value to the duplicate
  344. // SafeHandle need to happen atomically, so we contain them within a CER.
  345. RuntimeHelpers.PrepareConstrainedRegions();
  346. try { }
  347. finally {
  348. if (!CryptContextAddRef(this, IntPtr.Zero, 0)) {
  349. error = Marshal.GetLastWin32Error();
  350. }
  351. else {
  352. duplicate.SetHandle(originalHandle);
  353. }
  354. }
  355. // If we could not call CryptContextAddRef succesfully, then throw the error here otherwise
  356. // we should be in a valid state at this point.
  357. if (error != (int)CapiNative.ErrorCode.Success) {
  358. duplicate.Dispose();
  359. throw new CryptographicException(error);
  360. }
  361. else {
  362. Debug.Assert(!duplicate.IsInvalid, "Failed to duplicate handle successfully");
  363. }
  364. return duplicate;
  365. }
  366. finally {
  367. if (acquired) {
  368. DangerousRelease();
  369. }
  370. }
  371. }
  372. #if FEATURE_CORESYSTEM
  373. [System.Security.SecurityCritical]
  374. #endif
  375. protected override bool ReleaseHandle() {
  376. return CryptReleaseContext(handle, 0);
  377. }
  378. }
  379. }