/mcs/class/referencesource/System.Core/Microsoft/Win32/SafeHandles/CapiSafeHandles.cs
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
- // ==++==
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // ==--==
- using System;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Security.Cryptography;
- using System.Diagnostics.CodeAnalysis;
- using System.Diagnostics.Contracts;
- namespace Microsoft.Win32.SafeHandles {
- /// <summary>
- /// SafeHandle for buffers returned by the Axl APIs
- /// </summary>
- #if !FEATURE_CORESYSTEM
- #pragma warning disable 618 // Have not migrated to v4 transparency yet
- [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
- #pragma warning restore 618
- #endif
- internal sealed class SafeAxlBufferHandle : SafeHandleZeroOrMinusOneIsInvalid {
- private SafeAxlBufferHandle() : base(true) {
- return;
- }
- [DllImport("kernel32")]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- private static extern IntPtr GetProcessHeap();
- [DllImport("kernel32")]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool HeapFree(IntPtr hHeap, int dwFlags, IntPtr lpMem);
- protected override bool ReleaseHandle() {
- // _AxlFree is a wrapper around HeapFree on the process heap. Since it is not exported from mscorwks
- // we just call HeapFree directly. This needs to be updated if _AxlFree is ever changed.
- HeapFree(GetProcessHeap(), 0, handle);
- return true;
- }
- }
- /// <summary>
- /// SafeHandle base class for CAPI handles (such as HCRYPTKEY and HCRYPTHASH) which must keep their
- /// CSP alive as long as they stay alive as well. CAPI requires that all child handles belonging to a
- /// HCRYPTPROV must be destroyed up before the reference count to the HCRYPTPROV drops to zero.
- /// Since we cannot control the order of finalization between the two safe handles, SafeCapiHandleBase
- /// maintains a native refcount on its parent HCRYPTPROV to ensure that if the corresponding
- /// SafeCspKeyHandle is finalized first CAPI still keeps the provider alive.
- /// </summary>
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #else
- #pragma warning disable 618 // Have not migrated to v4 transparency yet
- [SecurityCritical(SecurityCriticalScope.Everything)]
- #pragma warning restore 618
- #endif
- internal abstract class SafeCapiHandleBase : SafeHandleZeroOrMinusOneIsInvalid {
- private IntPtr m_csp;
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- internal SafeCapiHandleBase() : base(true) {
- }
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- [DllImport("advapi32", SetLastError = true)]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CryptContextAddRef(IntPtr hProv,
- IntPtr pdwReserved,
- int dwFlags);
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- [DllImport("advapi32")]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
- protected IntPtr ParentCsp {
- get { return m_csp; }
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- #endif
- set {
- // We should not be resetting the parent CSP if it's already been set once - that will
- // lead to leaking the original handle.
- Debug.Assert(m_csp == IntPtr.Zero);
-
- int error = (int)CapiNative.ErrorCode.Success;
-
- // A successful call to CryptContextAddRef and an assignment of the handle value to our field
- // SafeHandle need to happen atomically, so we contain them within a CER.
- RuntimeHelpers.PrepareConstrainedRegions();
- try { }
- finally {
- if (CryptContextAddRef(value, IntPtr.Zero, 0)) {
- m_csp = value;
- }
- else {
- error = Marshal.GetLastWin32Error();
- }
- }
-
- if (error != (int)CapiNative.ErrorCode.Success) {
- throw new CryptographicException(error);
- }
- }
- }
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
- #endif
- internal void SetParentCsp(SafeCspHandle parentCsp) {
- bool addedRef = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- parentCsp.DangerousAddRef(ref addedRef);
- IntPtr rawParentHandle = parentCsp.DangerousGetHandle();
- ParentCsp = rawParentHandle;
- }
- finally {
- if (addedRef) {
- parentCsp.DangerousRelease();
- }
- }
- }
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- protected abstract bool ReleaseCapiChildHandle();
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- protected override sealed bool ReleaseHandle() {
- // Order is important here - we must destroy the child handle before the parent CSP
- bool destroyedChild = ReleaseCapiChildHandle();
- bool releasedCsp = true;
- if (m_csp != IntPtr.Zero) {
- releasedCsp = CryptReleaseContext(m_csp, 0);
- }
- return destroyedChild && releasedCsp;
- }
- }
- /// <summary>
- /// SafeHandle for CAPI hash algorithms (HCRYPTHASH)
- /// </summary>
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #else
- #pragma warning disable 618 // Have not migrated to v4 transparency yet
- [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
- #pragma warning restore 618
- #endif
- internal sealed class SafeCapiHashHandle : SafeCapiHandleBase {
- private static volatile SafeCapiHashHandle s_invalidHandle;
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- private SafeCapiHashHandle() {
- }
- /// <summary>
- /// NULL hash handle
- /// </summary>
- public static SafeCapiHashHandle InvalidHandle {
- get {
- if (s_invalidHandle == null) {
- // More than one of these might get created in parallel, but that's okay.
- // Saving one to the field saves on GC tracking, but by SuppressingFinalize on
- // any instance returned there's already less finalization pressure.
- SafeCapiHashHandle handle = new SafeCapiHashHandle();
- handle.SetHandle(IntPtr.Zero);
- GC.SuppressFinalize(handle);
- s_invalidHandle = handle;
- }
- return s_invalidHandle;
- }
- }
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- [DllImport("advapi32")]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CryptDestroyHash(IntPtr hHash);
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- protected override bool ReleaseCapiChildHandle() {
- return CryptDestroyHash(handle);
- }
- }
- /// <summary>
- /// SafeHandle for CAPI keys (HCRYPTKEY)
- /// </summary>
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #else
- #pragma warning disable 618 // Have not migrated to v4 transparency yet
- [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
- #pragma warning restore 618
- #endif
- internal sealed class SafeCapiKeyHandle : SafeCapiHandleBase {
- private static volatile SafeCapiKeyHandle s_invalidHandle;
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- private SafeCapiKeyHandle() {
- }
- /// <summary>
- /// NULL key handle
- /// </summary>
- internal static SafeCapiKeyHandle InvalidHandle {
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- get {
- if (s_invalidHandle == null) {
- // More than one of these might get created in parallel, but that's okay.
- // Saving one to the field saves on GC tracking, but by SuppressingFinalize on
- // any instance returned there's already less finalization pressure.
- SafeCapiKeyHandle handle = new SafeCapiKeyHandle();
- handle.SetHandle(IntPtr.Zero);
- GC.SuppressFinalize(handle);
- s_invalidHandle = handle;
- }
- return s_invalidHandle;
- }
- }
- [DllImport("advapi32")]
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #else
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CryptDestroyKey(IntPtr hKey);
- /// <summary>
- /// Make a copy of this key handle
- /// </summary>
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- internal SafeCapiKeyHandle Duplicate() {
- Contract.Requires(!IsInvalid && !IsClosed);
- Contract.Ensures(Contract.Result<SafeCapiKeyHandle>() != null && !Contract.Result<SafeCapiKeyHandle>().IsInvalid && !Contract.Result<SafeCapiKeyHandle>().IsClosed);
- SafeCapiKeyHandle duplicate = null;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- if (!CapiNative.UnsafeNativeMethods.CryptDuplicateKey(this, IntPtr.Zero, 0, out duplicate)) {
- throw new CryptographicException(Marshal.GetLastWin32Error());
- }
- }
- finally {
- if (duplicate != null && !duplicate.IsInvalid && ParentCsp != IntPtr.Zero) {
- duplicate.ParentCsp = ParentCsp;
- }
- }
- return duplicate;
- }
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- protected override bool ReleaseCapiChildHandle() {
- return CryptDestroyKey(handle);
- }
- }
- /// <summary>
- /// SafeHandle for crypto service providers (HCRYPTPROV)
- /// </summary>
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #else
- #pragma warning disable 618 // Have not migrated to v4 transparency yet
- [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
- #pragma warning restore 618
- #endif
- internal sealed class SafeCspHandle : SafeHandleZeroOrMinusOneIsInvalid {
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- private SafeCspHandle() : base(true) {
- return;
- }
- [DllImport("advapi32", SetLastError = true)]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CryptContextAddRef(SafeCspHandle hProv,
- IntPtr pdwReserved,
- int dwFlags);
- [DllImport("advapi32")]
- #if !FEATURE_CORESYSTEM
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- #endif
- [SuppressUnmanagedCodeSecurity]
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CryptReleaseContext(IntPtr hProv, int dwFlags);
- /// <summary>
- /// Create a second SafeCspHandle which refers to the same HCRYPTPROV
- /// </summary>
- [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- public SafeCspHandle Duplicate() {
- Contract.Requires(!IsInvalid && !IsClosed);
- // In the window between the call to CryptContextAddRef and when the raw handle value is assigned
- // into this safe handle, there's a second reference to the original safe handle that the CLR does
- // not know about, so we need to bump the reference count around this entire operation to ensure
- // that we don't have the original handle closed underneath us.
- bool acquired = false;
- RuntimeHelpers.PrepareConstrainedRegions();
- try {
- DangerousAddRef(ref acquired);
- IntPtr originalHandle = DangerousGetHandle();
- int error = (int)CapiNative.ErrorCode.Success;
- SafeCspHandle duplicate = new SafeCspHandle();
- // A successful call to CryptContextAddRef and an assignment of the handle value to the duplicate
- // SafeHandle need to happen atomically, so we contain them within a CER.
- RuntimeHelpers.PrepareConstrainedRegions();
- try { }
- finally {
- if (!CryptContextAddRef(this, IntPtr.Zero, 0)) {
- error = Marshal.GetLastWin32Error();
- }
- else {
- duplicate.SetHandle(originalHandle);
- }
- }
- // If we could not call CryptContextAddRef succesfully, then throw the error here otherwise
- // we should be in a valid state at this point.
- if (error != (int)CapiNative.ErrorCode.Success) {
- duplicate.Dispose();
- throw new CryptographicException(error);
- }
- else {
- Debug.Assert(!duplicate.IsInvalid, "Failed to duplicate handle successfully");
- }
- return duplicate;
- }
- finally {
- if (acquired) {
- DangerousRelease();
- }
- }
- }
- #if FEATURE_CORESYSTEM
- [System.Security.SecurityCritical]
- #endif
- protected override bool ReleaseHandle() {
- return CryptReleaseContext(handle, 0);
- }
- }
- }