Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / Microsoft / Win32 / SafeHandles / NCryptSafeHandles.cs / 1305376 / NCryptSafeHandles.cs
// ==++==
//
// 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.Permissions;
using System.Diagnostics.Contracts;
namespace Microsoft.Win32.SafeHandles {
///
/// Base class for NCrypt handles which need to support being pseudo-duplicated. This class is not for
/// external use (instead applications should consume the concrete subclasses of this class).
///
///
/// Since NCrypt handles do not have a native DuplicateHandle type call, we need to do manual
/// reference counting in managed code whenever we hand out an extra reference to one of these handles.
/// This class wraps up the logic to correctly duplicate and free these handles to simluate a native
/// duplication.
///
/// Each open handle object can be thought of as being in one of three states:
/// 1. Owner - created via the marshaler, traditional style safe handle. Notably, only one owner
/// handle exists for a given native handle.
/// 2. Duplicate - points at a handle in the Holder state. Releasing a handle in the duplicate state
/// results only in decrementing the reference count of the holder, not in a release
/// of the native handle.
/// 3. Holder - holds onto a native handle and is referenced by handles in the duplicate state.
/// When all duplicate handles are closed, the holder handle releases the native
/// handle. A holder handle will never be finalized, since this results in a ----
/// between the finalizers of the duplicate handles and the holder handle. Instead,
/// it relies upon all of the duplicate handles to be finalized and decriment the
/// ref count to zero. Instances of a holder handle should never be referenced by
/// anything but a duplicate handle.
///
//
//
//
#pragma warning disable 618 // Have not migrated to v4 transparency yet
[System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
#pragma warning restore 618
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public abstract class SafeNCryptHandle : SafeHandleZeroOrMinusOneIsInvalid {
private enum OwnershipState {
///
/// The safe handle owns the native handle outright. This must be value 0, as this is the
/// state the marshaler will place the handle in when marshaling back a SafeHandle
///
Owner = 0,
///
/// The safe handle does not own the native handle, but points to a Holder which does
///
Duplicate,
///
/// The safe handle owns the native handle, but shares it with other Duplicate handles
///
Holder
}
private OwnershipState m_ownershipState;
///
/// If the handle is a Duplicate, this points at the safe handle which actually owns the native handle.
///
private SafeNCryptHandle m_holder;
protected SafeNCryptHandle() : base(true) {
return;
}
///
/// Wrapper for the m_holder field which ensures that we're in a consistent state
///
private SafeNCryptHandle Holder {
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get {
Contract.Requires((m_ownershipState == OwnershipState.Duplicate && m_holder != null) ||
(m_ownershipState != OwnershipState.Duplicate && m_holder == null));
Contract.Requires(m_holder == null || m_holder.m_ownershipState == OwnershipState.Holder);
return m_holder;
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
set {
Contract.Ensures(m_holder.m_ownershipState == OwnershipState.Holder);
Contract.Ensures(m_ownershipState == OwnershipState.Duplicate);
#if DEBUG
Contract.Ensures(IsValidOpenState);
Contract.Assert(value.IsValidOpenState);
#endif
Contract.Assert(m_ownershipState != OwnershipState.Duplicate);
Contract.Assert(value.m_ownershipState == OwnershipState.Holder);
m_holder = value;
m_ownershipState = OwnershipState.Duplicate;
}
}
#if DEBUG
///
/// Ensure the state of the handle is consistent for an open handle
///
private bool IsValidOpenState {
[Pure]
get {
switch (m_ownershipState) {
// Owner handles do not have a holder
case OwnershipState.Owner:
return Holder == null && !IsInvalid && !IsClosed;
// Duplicate handles have valid open holders with the same raw handle value
case OwnershipState.Duplicate:
bool acquiredHolder = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
IntPtr holderRawHandle = IntPtr.Zero;
if (Holder != null) {
Holder.DangerousAddRef(ref acquiredHolder);
holderRawHandle = Holder.DangerousGetHandle();
}
bool holderValid = Holder != null &&
!Holder.IsInvalid &&
!Holder.IsClosed &&
holderRawHandle != IntPtr.Zero &&
holderRawHandle == handle;
return holderValid && !IsInvalid && !IsClosed;
}
finally {
if (acquiredHolder) {
Holder.DangerousRelease();
}
}
// Holder handles do not have a holder
case OwnershipState.Holder:
return Holder == null && !IsInvalid && !IsClosed;
// Unknown ownership state
default:
return false;
}
}
}
#endif
///
/// Duplicate a handle
///
///
/// #NCryptHandleDuplicationAlgorithm
///
/// Duplicating a handle performs different operations depending upon the state of the handle:
///
/// * Owner - Allocate two new handles, a holder and a duplicate.
/// - Suppress finalization on the holder
/// - Transition into the duplicate state
/// - Use the new holder as the holder for both this handle and the duplicate
/// - Increment the reference count on the holder
///
/// * Duplicate - Allocate a duplicate handle
/// - Increment the reference count of our holder
/// - Assign the duplicate's holder to be our holder
///
/// * Holder - Specifically disallowed. Holders should only ever be referenced by duplicates,
/// so duplication will occur on the duplicate rather than the holder handle.
///
internal T Duplicate() where T : SafeNCryptHandle, new() {
// Spec#: Consider adding a model variable for ownership state?
Contract.Ensures(Contract.Result() != null);
Contract.Ensures(m_ownershipState == OwnershipState.Duplicate);
Contract.Ensures(Contract.Result().m_ownershipState == OwnershipState.Duplicate);
#if DEBUG
// Spec#: Consider a debug-only? model variable for IsValidOpenState?
Contract.Ensures(Contract.Result().IsValidOpenState);
Contract.Ensures(IsValidOpenState);
Contract.Assert(IsValidOpenState);
#endif
Contract.Assert(m_ownershipState != OwnershipState.Holder);
Contract.Assert(typeof(T) == this.GetType());
if (m_ownershipState == OwnershipState.Owner) {
return DuplicateOwnerHandle();
}
else {
// If we're not an owner handle, and we're being duplicated then we must be a duplicate handle.
return DuplicateDuplicatedHandle();
}
}
///
/// Duplicate a safe handle which is already duplicated.
///
/// See code:Microsoft.Win32.SafeHandles.SafeNCryptHandle#NCryptHandleDuplicationAlgorithm for
/// details about the algorithm.
///
private T DuplicateDuplicatedHandle() where T : SafeNCryptHandle, new() {
Contract.Ensures(m_ownershipState == OwnershipState.Duplicate);
Contract.Ensures(Contract.Result() != null &&
Contract.Result().m_ownershipState == OwnershipState.Duplicate);
#if DEBUG
Contract.Ensures(IsValidOpenState);
Contract.Ensures(Contract.Result().IsValidOpenState);
Contract.Assert(IsValidOpenState);
#endif
Contract.Assert(m_ownershipState == OwnershipState.Duplicate);
Contract.Assert(typeof(T) == this.GetType());
bool addedRef = false;
T duplicate = new T();
// We need to do this operation in a CER, since we need to make sure that if the AddRef occurs
// that the duplicated handle will always point back to the Holder, otherwise the Holder will leak
// since it will never have its ref count reduced to zero.
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally {
Holder.DangerousAddRef(ref addedRef);
duplicate.SetHandle(Holder.DangerousGetHandle());
duplicate.Holder = Holder; // Transitions to OwnershipState.Duplicate
}
return duplicate;
}
///
/// Duplicate a safe handle which is currently the exclusive owner of a native handle
///
/// See code:Microsoft.Win32.SafeHandles.SafeNCryptHandle#NCryptHandleDuplicationAlgorithm for
/// details about the algorithm.
///
private T DuplicateOwnerHandle() where T : SafeNCryptHandle, new() {
Contract.Ensures(m_ownershipState == OwnershipState.Duplicate);
Contract.Ensures(Contract.Result() != null &&
Contract.Result().m_ownershipState == OwnershipState.Duplicate);
#if DEBUG
Contract.Ensures(IsValidOpenState);
Contract.Ensures(Contract.Result().IsValidOpenState);
Contract.Assert(IsValidOpenState);
#endif
Contract.Assert(m_ownershipState == OwnershipState.Owner);
Contract.Assert(typeof(T) == this.GetType());
bool addRef = false;
T holder = new T();
T duplicate = new T();
// We need to do this operation in a CER in order to ensure that everybody's state stays consistent
// with the current view of the world. If the state of the various handles gets out of [....], then
// we'll end up leaking since reference counts will not be set up properly.
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally {
// Setup a holder safe handle to ref count the native handle
holder.m_ownershipState = OwnershipState.Holder;
holder.SetHandle(DangerousGetHandle());
GC.SuppressFinalize(holder);
// Transition into the duplicate state, referencing the holder. The initial reference count
// on the holder will refer to the original handle so there is no need to AddRef here.
Holder = holder; // Transitions to OwnershipState.Duplicate
// The duplicate handle will also reference the holder
holder.DangerousAddRef(ref addRef);
duplicate.SetHandle(holder.DangerousGetHandle());
duplicate.Holder = holder; // Transitions to OwnershipState.Duplicate
}
return duplicate;
}
///
/// Release the handle
///
///
/// Similar to duplication, releasing a handle performs different operations based upon the state
/// of the handle.
///
/// * Owner - Simply call the release P/Invoke method
/// * Duplicate - Decrement the reference count of the current holder
/// * Holder - Call the release P/Invoke. Note that ReleaseHandle on a holder implies a reference
/// count of zero.
///
protected override bool ReleaseHandle() {
if (m_ownershipState == OwnershipState.Duplicate) {
Holder.DangerousRelease();
return true;
}
else {
return ReleaseNativeHandle();
}
}
///
/// Perform the actual release P/Invoke
///
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected abstract bool ReleaseNativeHandle();
}
///
/// Safe handle representing an NCRYPT_KEY_HANDLE
///
//
//
//
#pragma warning disable 618 // Have not migrated to v4 transparency yet
[System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
#pragma warning restore 618
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public sealed class SafeNCryptKeyHandle : SafeNCryptHandle {
[DllImport("ncrypt.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
private static extern int NCryptFreeObject(IntPtr hObject);
internal SafeNCryptKeyHandle Duplicate() {
return Duplicate();
}
protected override bool ReleaseNativeHandle() {
return NCryptFreeObject(handle) == 0;
}
}
///
/// Safe handle representing an NCRYPT_PROV_HANDLE
///
//
//
//
#pragma warning disable 618 // Have not migrated to v4 transparency yet
[System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
#pragma warning restore 618
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public sealed class SafeNCryptProviderHandle : SafeNCryptHandle {
[DllImport("ncrypt.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
private static extern int NCryptFreeObject(IntPtr hObject);
internal SafeNCryptProviderHandle Duplicate() {
return Duplicate();
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal void SetHandleValue(IntPtr newHandleValue) {
Contract.Requires(newHandleValue != IntPtr.Zero);
Contract.Requires(!IsClosed);
Contract.Ensures(!IsInvalid);
Contract.Assert(handle == IntPtr.Zero);
SetHandle(newHandleValue);
}
protected override bool ReleaseNativeHandle() {
return NCryptFreeObject(handle) == 0;
}
}
///
/// Safe handle representing an NCRYPT_SECRET_HANDLE
///
//
//
//
#pragma warning disable 618 // Have not migrated to v4 transparency yet
[System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
#pragma warning restore 618
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public sealed class SafeNCryptSecretHandle : SafeNCryptHandle {
[DllImport("ncrypt.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
private static extern int NCryptFreeObject(IntPtr hObject);
protected override bool ReleaseNativeHandle() {
return NCryptFreeObject(handle) == 0;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HostedTransportConfigurationManager.cs
- COM2ColorConverter.cs
- NodeInfo.cs
- WindowsAltTab.cs
- ProfileProvider.cs
- IdnMapping.cs
- SectionVisual.cs
- FlowDocumentReader.cs
- BuildProvider.cs
- ImportCatalogPart.cs
- SeekStoryboard.cs
- ProtocolsConfiguration.cs
- DataListItemCollection.cs
- WorkflowMarkupElementEventArgs.cs
- ProvidersHelper.cs
- CompilerState.cs
- ColorConvertedBitmapExtension.cs
- MailHeaderInfo.cs
- ZipFileInfoCollection.cs
- DataSourceSelectArguments.cs
- XmlSchemaSimpleContentRestriction.cs
- IResourceProvider.cs
- EditorPartCollection.cs
- X509Utils.cs
- AttachmentCollection.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- SocketCache.cs
- HoistedLocals.cs
- ByteStack.cs
- listitem.cs
- DbConnectionPoolOptions.cs
- FontStyleConverter.cs
- ProcessInfo.cs
- Code.cs
- FolderLevelBuildProvider.cs
- CodeSnippetTypeMember.cs
- BamlLocalizableResource.cs
- TreeViewImageIndexConverter.cs
- ResponseStream.cs
- RetrieveVirtualItemEventArgs.cs
- UnSafeCharBuffer.cs
- ScopedMessagePartSpecification.cs
- RequestStatusBarUpdateEventArgs.cs
- EmptyControlCollection.cs
- SqlStream.cs
- CheckBoxBaseAdapter.cs
- SoapExtension.cs
- PolyQuadraticBezierSegment.cs
- ContractTypeNameCollection.cs
- URIFormatException.cs
- ToggleButton.cs
- TogglePatternIdentifiers.cs
- IssuedTokenClientBehaviorsElement.cs
- DataSysAttribute.cs
- CodeCastExpression.cs
- AsyncResult.cs
- BeginStoryboard.cs
- ButtonAutomationPeer.cs
- PartitionResolver.cs
- MailMessageEventArgs.cs
- sqlinternaltransaction.cs
- WmlPageAdapter.cs
- Profiler.cs
- HyperlinkAutomationPeer.cs
- TypeDelegator.cs
- BinHexEncoder.cs
- TextChange.cs
- SetterBaseCollection.cs
- DrawingGroupDrawingContext.cs
- RectValueSerializer.cs
- FlatButtonAppearance.cs
- TextView.cs
- OleDbConnection.cs
- shaperfactoryquerycachekey.cs
- WindowsScroll.cs
- HostDesigntimeLicenseContext.cs
- StatusBarPanelClickEvent.cs
- SafeWaitHandle.cs
- ComponentResourceKeyConverter.cs
- CustomAttributeBuilder.cs
- TextElementCollection.cs
- UnaryNode.cs
- HtmlControlPersistable.cs
- AuthenticationService.cs
- IDictionary.cs
- CellTreeNode.cs
- PersistenceTypeAttribute.cs
- FontWeight.cs
- ResourcesBuildProvider.cs
- OleDbFactory.cs
- PreviewPrintController.cs
- ItemMap.cs
- HttpResponseHeader.cs
- Identifier.cs
- FaultException.cs
- SQLMoney.cs
- StorageFunctionMapping.cs
- SqlBuilder.cs
- DrawItemEvent.cs
- LockedActivityGlyph.cs