3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 using System.Diagnostics;
9 using System.Runtime.CompilerServices;
10 using System.Runtime.ConstrainedExecution;
11 using System.Runtime.InteropServices;
12 using System.Security;
13 using System.Security.Cryptography;
14 using System.Diagnostics.CodeAnalysis;
15 using System.Diagnostics.Contracts;
17 namespace Microsoft.Win32.SafeHandles {
19 /// SafeHandle for buffers returned by the Axl APIs
21 #if !FEATURE_CORESYSTEM
22 #pragma warning disable 618 // Have not migrated to v4 transparency yet
23 [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
24 #pragma warning restore 618
26 internal sealed class SafeAxlBufferHandle : SafeHandleZeroOrMinusOneIsInvalid {
27 private SafeAxlBufferHandle() : base(true) {
31 [DllImport("kernel32")]
32 #if !FEATURE_CORESYSTEM
33 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
35 [SuppressUnmanagedCodeSecurity]
36 private static extern IntPtr GetProcessHeap();
38 [DllImport("kernel32")]
39 #if !FEATURE_CORESYSTEM
40 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
42 [SuppressUnmanagedCodeSecurity]
43 [return: MarshalAs(UnmanagedType.Bool)]
44 private static extern bool HeapFree(IntPtr hHeap, int dwFlags, IntPtr lpMem);
46 protected override bool ReleaseHandle() {
47 // _AxlFree is a wrapper around HeapFree on the process heap. Since it is not exported from mscorwks
48 // we just call HeapFree directly. This needs to be updated if _AxlFree is ever changed.
49 HeapFree(GetProcessHeap(), 0, handle);
55 /// SafeHandle base class for CAPI handles (such as HCRYPTKEY and HCRYPTHASH) which must keep their
56 /// CSP alive as long as they stay alive as well. CAPI requires that all child handles belonging to a
57 /// HCRYPTPROV must be destroyed up before the reference count to the HCRYPTPROV drops to zero.
58 /// Since we cannot control the order of finalization between the two safe handles, SafeCapiHandleBase
59 /// maintains a native refcount on its parent HCRYPTPROV to ensure that if the corresponding
60 /// SafeCspKeyHandle is finalized first CAPI still keeps the provider alive.
62 #if FEATURE_CORESYSTEM
63 [System.Security.SecurityCritical]
65 #pragma warning disable 618 // Have not migrated to v4 transparency yet
66 [SecurityCritical(SecurityCriticalScope.Everything)]
67 #pragma warning restore 618
69 internal abstract class SafeCapiHandleBase : SafeHandleZeroOrMinusOneIsInvalid {
72 #if FEATURE_CORESYSTEM
73 [System.Security.SecurityCritical]
75 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
76 internal SafeCapiHandleBase() : base(true) {
79 #if FEATURE_CORESYSTEM
80 [System.Security.SecurityCritical]
82 [DllImport("advapi32", SetLastError = true)]
83 #if !FEATURE_CORESYSTEM
84 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
86 [SuppressUnmanagedCodeSecurity]
87 [return: MarshalAs(UnmanagedType.Bool)]
88 private static extern bool CryptContextAddRef(IntPtr hProv,
92 #if FEATURE_CORESYSTEM
93 [System.Security.SecurityCritical]
95 [DllImport("advapi32")]
96 #if !FEATURE_CORESYSTEM
97 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
99 [SuppressUnmanagedCodeSecurity]
100 [return: MarshalAs(UnmanagedType.Bool)]
101 private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
104 protected IntPtr ParentCsp {
105 get { return m_csp; }
107 #if !FEATURE_CORESYSTEM
108 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
111 // We should not be resetting the parent CSP if it's already been set once - that will
112 // lead to leaking the original handle.
113 Debug.Assert(m_csp == IntPtr.Zero);
115 int error = (int)CapiNative.ErrorCode.Success;
117 // A successful call to CryptContextAddRef and an assignment of the handle value to our field
118 // SafeHandle need to happen atomically, so we contain them within a CER.
119 RuntimeHelpers.PrepareConstrainedRegions();
122 if (CryptContextAddRef(value, IntPtr.Zero, 0)) {
126 error = Marshal.GetLastWin32Error();
130 if (error != (int)CapiNative.ErrorCode.Success) {
131 throw new CryptographicException(error);
136 #if FEATURE_CORESYSTEM
137 [System.Security.SecurityCritical]
139 #if !FEATURE_CORESYSTEM
140 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
142 internal void SetParentCsp(SafeCspHandle parentCsp) {
143 bool addedRef = false;
144 RuntimeHelpers.PrepareConstrainedRegions();
146 parentCsp.DangerousAddRef(ref addedRef);
147 IntPtr rawParentHandle = parentCsp.DangerousGetHandle();
148 ParentCsp = rawParentHandle;
152 parentCsp.DangerousRelease();
157 #if FEATURE_CORESYSTEM
158 [System.Security.SecurityCritical]
160 protected abstract bool ReleaseCapiChildHandle();
162 #if FEATURE_CORESYSTEM
163 [System.Security.SecurityCritical]
165 protected override sealed bool ReleaseHandle() {
166 // Order is important here - we must destroy the child handle before the parent CSP
167 bool destroyedChild = ReleaseCapiChildHandle();
168 bool releasedCsp = true;
170 if (m_csp != IntPtr.Zero) {
171 releasedCsp = CryptReleaseContext(m_csp, 0);
174 return destroyedChild && releasedCsp;
179 /// SafeHandle for CAPI hash algorithms (HCRYPTHASH)
181 #if FEATURE_CORESYSTEM
182 [System.Security.SecurityCritical]
184 #pragma warning disable 618 // Have not migrated to v4 transparency yet
185 [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
186 #pragma warning restore 618
188 internal sealed class SafeCapiHashHandle : SafeCapiHandleBase {
189 #if FEATURE_CORESYSTEM
190 [System.Security.SecurityCritical]
192 private SafeCapiHashHandle() {
198 public static SafeCapiHashHandle InvalidHandle {
200 SafeCapiHashHandle handle = new SafeCapiHashHandle();
201 handle.SetHandle(IntPtr.Zero);
206 #if FEATURE_CORESYSTEM
207 [System.Security.SecurityCritical]
209 [DllImport("advapi32")]
210 #if !FEATURE_CORESYSTEM
211 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
213 [SuppressUnmanagedCodeSecurity]
214 [return: MarshalAs(UnmanagedType.Bool)]
215 private static extern bool CryptDestroyHash(IntPtr hHash);
217 #if FEATURE_CORESYSTEM
218 [System.Security.SecurityCritical]
220 protected override bool ReleaseCapiChildHandle() {
221 return CryptDestroyHash(handle);
226 /// SafeHandle for CAPI keys (HCRYPTKEY)
228 #if FEATURE_CORESYSTEM
229 [System.Security.SecurityCritical]
231 #pragma warning disable 618 // Have not migrated to v4 transparency yet
232 [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
233 #pragma warning restore 618
235 internal sealed class SafeCapiKeyHandle : SafeCapiHandleBase {
236 #if FEATURE_CORESYSTEM
237 [System.Security.SecurityCritical]
239 private SafeCapiKeyHandle() {
245 internal static SafeCapiKeyHandle InvalidHandle {
246 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
248 SafeCapiKeyHandle handle = new SafeCapiKeyHandle();
249 handle.SetHandle(IntPtr.Zero);
254 [DllImport("advapi32")]
255 #if FEATURE_CORESYSTEM
256 [System.Security.SecurityCritical]
258 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
260 [SuppressUnmanagedCodeSecurity]
261 [return: MarshalAs(UnmanagedType.Bool)]
262 private static extern bool CryptDestroyKey(IntPtr hKey);
265 /// Make a copy of this key handle
267 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
268 #if FEATURE_CORESYSTEM
269 [System.Security.SecurityCritical]
271 internal SafeCapiKeyHandle Duplicate() {
272 Contract.Requires(!IsInvalid && !IsClosed);
273 Contract.Ensures(Contract.Result<SafeCapiKeyHandle>() != null && !Contract.Result<SafeCapiKeyHandle>().IsInvalid && !Contract.Result<SafeCapiKeyHandle>().IsClosed);
275 SafeCapiKeyHandle duplicate = null;
277 RuntimeHelpers.PrepareConstrainedRegions();
279 if (!CapiNative.UnsafeNativeMethods.CryptDuplicateKey(this, IntPtr.Zero, 0, out duplicate)) {
280 throw new CryptographicException(Marshal.GetLastWin32Error());
284 if (duplicate != null && !duplicate.IsInvalid && ParentCsp != IntPtr.Zero) {
285 duplicate.ParentCsp = ParentCsp;
292 #if FEATURE_CORESYSTEM
293 [System.Security.SecurityCritical]
295 protected override bool ReleaseCapiChildHandle() {
296 return CryptDestroyKey(handle);
301 /// SafeHandle for crypto service providers (HCRYPTPROV)
303 #if FEATURE_CORESYSTEM
304 [System.Security.SecurityCritical]
306 #pragma warning disable 618 // Have not migrated to v4 transparency yet
307 [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
308 #pragma warning restore 618
310 internal sealed class SafeCspHandle : SafeHandleZeroOrMinusOneIsInvalid {
311 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
312 #if FEATURE_CORESYSTEM
313 [System.Security.SecurityCritical]
315 private SafeCspHandle() : base(true) {
319 [DllImport("advapi32", SetLastError = true)]
320 #if !FEATURE_CORESYSTEM
321 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
323 [SuppressUnmanagedCodeSecurity]
324 #if FEATURE_CORESYSTEM
325 [System.Security.SecurityCritical]
327 [return: MarshalAs(UnmanagedType.Bool)]
328 private static extern bool CryptContextAddRef(SafeCspHandle hProv,
332 [DllImport("advapi32")]
333 #if !FEATURE_CORESYSTEM
334 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
336 [SuppressUnmanagedCodeSecurity]
337 #if FEATURE_CORESYSTEM
338 [System.Security.SecurityCritical]
340 [return: MarshalAs(UnmanagedType.Bool)]
341 private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
344 /// Create a second SafeCspHandle which refers to the same HCRYPTPROV
346 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
347 #if FEATURE_CORESYSTEM
348 [System.Security.SecurityCritical]
350 public SafeCspHandle Duplicate() {
351 Contract.Requires(!IsInvalid && !IsClosed);
353 // In the window between the call to CryptContextAddRef and when the raw handle value is assigned
354 // into this safe handle, there's a second reference to the original safe handle that the CLR does
355 // not know about, so we need to bump the reference count around this entire operation to ensure
356 // that we don't have the original handle closed underneath us.
357 bool acquired = false;
358 RuntimeHelpers.PrepareConstrainedRegions();
360 DangerousAddRef(ref acquired);
361 IntPtr originalHandle = DangerousGetHandle();
363 int error = (int)CapiNative.ErrorCode.Success;
365 SafeCspHandle duplicate = new SafeCspHandle();
367 // A successful call to CryptContextAddRef and an assignment of the handle value to the duplicate
368 // SafeHandle need to happen atomically, so we contain them within a CER.
369 RuntimeHelpers.PrepareConstrainedRegions();
372 if (!CryptContextAddRef(this, IntPtr.Zero, 0)) {
373 error = Marshal.GetLastWin32Error();
376 duplicate.SetHandle(originalHandle);
380 // If we could not call CryptContextAddRef succesfully, then throw the error here otherwise
381 // we should be in a valid state at this point.
382 if (error != (int)CapiNative.ErrorCode.Success) {
384 throw new CryptographicException(error);
387 Debug.Assert(!duplicate.IsInvalid, "Failed to duplicate handle successfully");
399 #if FEATURE_CORESYSTEM
400 [System.Security.SecurityCritical]
402 protected override bool ReleaseHandle() {
403 return CryptReleaseContext(handle, 0);