Updated comments.
This commit is contained in:
@@ -7,16 +7,31 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reads and writes value types to byte arrays with explicit endianness.
|
||||||
|
/// </summary>
|
||||||
public static class ByteWriter
|
public static class ByteWriter
|
||||||
{
|
{
|
||||||
// Big endian: Most significant byte at lowest address in memory.
|
// Big endian: Most significant byte at lowest address in memory.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 2-byte signed integer to the buffer in big-endian format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write to the buffer.</param>
|
||||||
|
/// <param name="buffer">The buffer to write to.</param>
|
||||||
|
/// <param name="position">The index of the first byte to write to.</param>
|
||||||
public static void WriteInt16_BE( Int16 value, byte[] buffer, int position )
|
public static void WriteInt16_BE( Int16 value, byte[] buffer, int position )
|
||||||
{
|
{
|
||||||
buffer[position + 0] = (byte)( value >> 8 );
|
buffer[position + 0] = (byte)( value >> 8 );
|
||||||
buffer[position + 1] = (byte)( value );
|
buffer[position + 1] = (byte)( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 4-byte signed integer to the buffer in big-endian format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write to the buffer.</param>
|
||||||
|
/// <param name="buffer">The buffer to write to.</param>
|
||||||
|
/// <param name="position">The index of the first byte to write to.</param>
|
||||||
public static void WriteInt32_BE( Int32 value, byte[] buffer, int position )
|
public static void WriteInt32_BE( Int32 value, byte[] buffer, int position )
|
||||||
{
|
{
|
||||||
buffer[position + 0] = (byte)( value >> 24 );
|
buffer[position + 0] = (byte)( value >> 24 );
|
||||||
@@ -26,6 +41,13 @@ namespace NSspi
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a 2-byte signed integer that is stored in the buffer in big-endian format.
|
||||||
|
/// The returned value is in the native endianness.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The buffer to read.</param>
|
||||||
|
/// <param name="position">The index of the first byte to read.</param>
|
||||||
|
/// <returns></returns>
|
||||||
public static Int16 ReadInt16_BE( byte[] buffer, int position )
|
public static Int16 ReadInt16_BE( byte[] buffer, int position )
|
||||||
{
|
{
|
||||||
Int16 value;
|
Int16 value;
|
||||||
@@ -36,6 +58,13 @@ namespace NSspi
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a 4-byte signed integer that is stored in the buffer in big-endian format.
|
||||||
|
/// The returned value is in the native endianness.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The buffer to read.</param>
|
||||||
|
/// <param name="position">The index of the first byte to read.</param>
|
||||||
|
/// <returns></returns>
|
||||||
public static Int32 ReadInt32_BE( byte[] buffer, int position )
|
public static Int32 ReadInt32_BE( byte[] buffer, int position )
|
||||||
{
|
{
|
||||||
Int32 value;
|
Int32 value;
|
||||||
@@ -47,6 +76,5 @@ namespace NSspi
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace NSspi.Credentials.Credentials
|
|||||||
internal struct QueryNameAttribCarrier
|
internal struct QueryNameAttribCarrier
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A pointer to a null-terminated ascii c-string containing the principle name
|
/// A pointer to a null-terminated ascii-encoded containing the principle name
|
||||||
/// associated with a credential
|
/// associated with a credential
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntPtr Name;
|
public IntPtr Name;
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ namespace NSspi.Credentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerCredential : CurrentCredential
|
public class ServerCredential : CurrentCredential
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
||||||
|
/// the current thread's security context.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="package">The name of the security package to obtain credentials from.</param>
|
||||||
public ServerCredential( string package )
|
public ServerCredential( string package )
|
||||||
: base( package, CredentialUse.Inbound )
|
: base( package, CredentialUse.Inbound )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,20 +11,6 @@ namespace NSspi
|
|||||||
{
|
{
|
||||||
internal static class NativeMethods
|
internal static class NativeMethods
|
||||||
{
|
{
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374713(v=vs.85).aspx
|
|
||||||
|
|
||||||
// The REMSSPI sample:
|
|
||||||
|
|
||||||
// A C++ pure client/server example:
|
|
||||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa380536(v=vs.85).aspx
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
SECURITY_STATUS SEC_Entry FreeContextBuffer(
|
|
||||||
_In_ PVOID pvContextBuffer
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
||||||
|
|||||||
@@ -6,12 +6,24 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides canonical names for security pacakges.
|
||||||
|
/// </summary>
|
||||||
public static class PackageNames
|
public static class PackageNames
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the Negotiate security package.
|
||||||
|
/// </summary>
|
||||||
public const string Negotiate = "Negotiate";
|
public const string Negotiate = "Negotiate";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the Kerberos security package.
|
||||||
|
/// </summary>
|
||||||
public const string Kerberos = "Kerberos";
|
public const string Kerberos = "Kerberos";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the NTLM security package.
|
||||||
|
/// </summary>
|
||||||
public const string Ntlm = "NTLM";
|
public const string Ntlm = "NTLM";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,16 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Queries information about security packages.
|
||||||
|
/// </summary>
|
||||||
public static class PackageSupport
|
public static class PackageSupport
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the properties of the named package.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="packageName">The name of the package.</param>
|
||||||
|
/// <returns></returns>
|
||||||
public static SecPkgInfo GetPackageCapabilities( string packageName )
|
public static SecPkgInfo GetPackageCapabilities( string packageName )
|
||||||
{
|
{
|
||||||
SecPkgInfo info;
|
SecPkgInfo info;
|
||||||
@@ -52,6 +60,10 @@ namespace NSspi
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of all known security package providers and their properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public static SecPkgInfo[] EnumeratePackages()
|
public static SecPkgInfo[] EnumeratePackages()
|
||||||
{
|
{
|
||||||
SecurityStatus status = SecurityStatus.InternalError;
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
|||||||
@@ -7,19 +7,51 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a native SecureBuffer structure, which is used for communicating
|
||||||
|
/// buffers to the native APIs.
|
||||||
|
/// </summary>
|
||||||
[StructLayout( LayoutKind.Sequential )]
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
internal struct SecureBufferInternal
|
internal struct SecureBufferInternal
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// When provided to the native API, the total number of bytes available in the buffer.
|
||||||
|
/// On return from the native API, the number of bytes that were filled or used by the
|
||||||
|
/// native API.
|
||||||
|
/// </summary>
|
||||||
public int Count;
|
public int Count;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type or purpose of the buffer.
|
||||||
|
/// </summary>
|
||||||
public BufferType Type;
|
public BufferType Type;
|
||||||
|
|
||||||
// A pointer to a byte[]
|
/// <summary>
|
||||||
|
/// An pointer to a pinned byte[] buffer.
|
||||||
|
/// </summary>
|
||||||
public IntPtr Buffer;
|
public IntPtr Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores buffers to provide tokens and data to the native SSPI APIs.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The buffer is translated into a SecureBufferInternal for the actual call.
|
||||||
|
/// To keep the call setup code simple, and to centralize the buffer pinning code,
|
||||||
|
/// this class stores and returns buffers as regular byte arrays. The buffer
|
||||||
|
/// pinning support code in SecureBufferAdapter handles conversion to SecureBufferInternal
|
||||||
|
/// for pass to the managed api, as well as pinning relevant chunks of memory.
|
||||||
|
///
|
||||||
|
/// Furthermore, the native API may not use the entire buffer, and so a mechanism
|
||||||
|
/// is needed to communicate the usage of the buffer separate from the length
|
||||||
|
/// of the buffer.</remarks>
|
||||||
internal class SecureBuffer
|
internal class SecureBuffer
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the SecureBuffer class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The buffer to wrap.</param>
|
||||||
|
/// <param name="type">The type or purpose of the buffer, for purposes of
|
||||||
|
/// invoking the native API.</param>
|
||||||
public SecureBuffer( byte[] buffer, BufferType type )
|
public SecureBuffer( byte[] buffer, BufferType type )
|
||||||
{
|
{
|
||||||
this.Buffer = buffer;
|
this.Buffer = buffer;
|
||||||
@@ -27,10 +59,20 @@ namespace NSspi.Buffers
|
|||||||
this.Length = this.Buffer.Length;
|
this.Length = this.Buffer.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type or purposes of the API, for invoking the native API.
|
||||||
|
/// </summary>
|
||||||
public BufferType Type { get; set; }
|
public BufferType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer to provide to the native API.
|
||||||
|
/// </summary>
|
||||||
public byte[] Buffer { get; set; }
|
public byte[] Buffer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of elements that were actually filled or used by the native API,
|
||||||
|
/// which may be less than the total length of the buffer.
|
||||||
|
/// </summary>
|
||||||
public int Length { get; internal set; }
|
public int Length { get; internal set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,26 +8,109 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Prepares SecureBuffers for providing them to native API calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The native APIs consume lists of buffers, with each buffer indicating its type or purpose.
|
||||||
|
///
|
||||||
|
/// The buffers themselves are simple byte arrays, and the native APIs consume arrays of buffers.
|
||||||
|
///
|
||||||
|
/// Since winapi calling convention, perhaps as an extension of C calling convention, does not
|
||||||
|
/// provide a standard convention means of communicating the length of any array, custom structures
|
||||||
|
/// must be created to carry the buffer length and usage.
|
||||||
|
///
|
||||||
|
/// Not only does the API need to know how long each buffer is, and how long the array of buffers is,
|
||||||
|
/// it needs to communicate back how much of each buffer was filled; we may provide it a token buffer
|
||||||
|
/// that is 12288 bytes long, but it might only use 125 bytes of that, which we need a way of knowing.
|
||||||
|
///
|
||||||
|
/// As a result of this, the API requires byte arrays to be carried in structs that are natively known as
|
||||||
|
/// SecureBuffers (known as SecureBufferInternal in this project), and then arrays of SecureBuffers are
|
||||||
|
/// carried in a SecureBufferDescriptor structure.
|
||||||
|
///
|
||||||
|
/// As such, this class has to do a significant amount of marshaling work just to get the buffers back and
|
||||||
|
/// forth to the native APIs.
|
||||||
|
/// * We have to pin all buffers
|
||||||
|
/// * We have to pin the array of buffers
|
||||||
|
/// * We have to obtain IntPtr handles to each of the buffers and to the array of buffers.
|
||||||
|
/// * Since we provide EasyToUse SecureBuffer classes from the rest of the project, but we
|
||||||
|
/// provide SecureBufferInternal structures from the native API, we have to copy back values
|
||||||
|
/// from the SecureBufferInternal structs to our SecureBuffer class.
|
||||||
|
///
|
||||||
|
/// To make this class easy to use, it accepts either one or many buffers as its constructor; and
|
||||||
|
/// implements IDisposable to know when to marshal values back from the unmanaged structures and to
|
||||||
|
/// release pinned handles.
|
||||||
|
///
|
||||||
|
/// Additionally, in case the adapter is leaked without disposing, the adapter implements a Critical
|
||||||
|
/// Finalizer, to ensure that the GCHandles are released, else we will permanently pin handles.
|
||||||
|
///
|
||||||
|
/// The typical flow is to take one or many buffers; create and fill the neccessary unmanaged structures;
|
||||||
|
/// pin memory; acquire the IntPtr handles; let the caller access the top-level IntPtr representing
|
||||||
|
/// the SecureBufferDescriptor, to provide to the native APIs; wait for the caller to invoke the native
|
||||||
|
/// API; wait for the caller to invoke our Dispose; marshal back any data from the native structures
|
||||||
|
/// (buffer write counts); release all GCHandles to unpin memory.
|
||||||
|
///
|
||||||
|
/// The total descriptor structure is as follows:
|
||||||
|
/// |-- Descriptor handle
|
||||||
|
/// |-- Array of buffers
|
||||||
|
/// |-- Buffer 1
|
||||||
|
/// |-- Buffer 2
|
||||||
|
/// ...
|
||||||
|
/// |-- Buffer N.
|
||||||
|
///
|
||||||
|
/// Each object in that structure must be pinned and passed as an IntPtr to the native APIs.
|
||||||
|
/// All this to pass what boils down to a List of byte arrays..
|
||||||
|
/// </remarks>
|
||||||
internal sealed class SecureBufferAdapter : CriticalFinalizerObject, IDisposable
|
internal sealed class SecureBufferAdapter : CriticalFinalizerObject, IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the adapter has already been disposed.
|
||||||
|
/// </summary>
|
||||||
private bool disposed;
|
private bool disposed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of mananged SecureBuffers the caller provided to us.
|
||||||
|
/// </summary>
|
||||||
private IList<SecureBuffer> buffers;
|
private IList<SecureBuffer> buffers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The top level handle representing the entire descriptor.
|
||||||
|
/// </summary>
|
||||||
private GCHandle descriptorHandle;
|
private GCHandle descriptorHandle;
|
||||||
|
|
||||||
private GCHandle[] bufferHandles;
|
/// <summary>
|
||||||
|
/// The handle representing the array of buffers.
|
||||||
private SecureBufferDescInternal descriptor;
|
/// </summary>
|
||||||
private SecureBufferInternal[] bufferCarrier;
|
|
||||||
private GCHandle bufferCarrierHandle;
|
private GCHandle bufferCarrierHandle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The handles representing each actual buffer.
|
||||||
|
/// </summary>
|
||||||
|
private GCHandle[] bufferHandles;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The native buffer descriptor
|
||||||
|
/// </summary>
|
||||||
|
private SecureBufferDescInternal descriptor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An array of the native buffers.
|
||||||
|
/// </summary>
|
||||||
|
private SecureBufferInternal[] bufferCarrier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a SecureBufferAdapter to carry a single buffer to the native api.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
public SecureBufferAdapter( SecureBuffer buffer )
|
public SecureBufferAdapter( SecureBuffer buffer )
|
||||||
: this( new[] { buffer } )
|
: this( new[] { buffer } )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the SecureBufferAdapter to carry a list of buffers to the native api.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffers"></param>
|
||||||
public SecureBufferAdapter( IList<SecureBuffer> buffers ) : base()
|
public SecureBufferAdapter( IList<SecureBuffer> buffers ) : base()
|
||||||
{
|
{
|
||||||
this.buffers = buffers;
|
this.buffers = buffers;
|
||||||
@@ -66,6 +149,9 @@ namespace NSspi.Buffers
|
|||||||
Dispose( false );
|
Dispose( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the top-level pointer to the secure buffer descriptor to pass to the native API.
|
||||||
|
/// </summary>
|
||||||
public IntPtr Handle
|
public IntPtr Handle
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -79,12 +165,22 @@ namespace NSspi.Buffers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Completes any buffer passing marshaling and releases all resources associated with the adapter.
|
||||||
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.Dispose( true );
|
this.Dispose( true );
|
||||||
GC.SuppressFinalize( this );
|
GC.SuppressFinalize( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Completes any buffer passing marshaling and releases all resources associated with the adapter.
|
||||||
|
/// This may be called by the finalizer, or by the regular Dispose method. In the case of the finalizer,
|
||||||
|
/// we've been leaked and there's no point in attempting to marshal back data from the native structures,
|
||||||
|
/// nor should we anyway since they may be gone.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">Whether Dispose is being called.</param>
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
private void Dispose( bool disposing )
|
private void Dispose( bool disposing )
|
||||||
{
|
{
|
||||||
@@ -121,6 +217,5 @@ namespace NSspi.Buffers
|
|||||||
|
|
||||||
this.disposed = true;
|
this.disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,20 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes how a buffer's opaque internals should be stored, with regards to byte ordering.
|
||||||
|
/// </summary>
|
||||||
internal enum SecureBufferDataRep : int
|
internal enum SecureBufferDataRep : int
|
||||||
{
|
{
|
||||||
/*
|
/// <summary>
|
||||||
#define SECURITY_NATIVE_DREP 0x00000010
|
/// Buffers internals are to be stored in the machine native byte order, which will change depending on
|
||||||
#define SECURITY_NETWORK_DREP 0x00000000
|
/// what machine generated the buffer.
|
||||||
*/
|
/// </summary>
|
||||||
Nativee = 0x10,
|
Native = 0x10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Buffers are stored in network byte ordering, that is, big endian format.
|
||||||
|
/// </summary>
|
||||||
Network = 0x00
|
Network = 0x00
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,31 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the native layout of the secure buffer descriptor that is provided directly
|
||||||
|
/// to native API calls.
|
||||||
|
/// </summary>
|
||||||
[StructLayout( LayoutKind.Sequential)]
|
[StructLayout( LayoutKind.Sequential)]
|
||||||
internal struct SecureBufferDescInternal
|
internal struct SecureBufferDescInternal
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer structure version.
|
||||||
|
/// </summary>
|
||||||
public int Version;
|
public int Version;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of buffers represented by this descriptor.
|
||||||
|
/// </summary>
|
||||||
public int NumBuffers;
|
public int NumBuffers;
|
||||||
|
|
||||||
// A pointer to a SecureBuffer[]
|
/// <summary>
|
||||||
|
/// A pointer to a array of buffers, where each buffer is a byte[].
|
||||||
|
/// </summary>
|
||||||
public IntPtr Buffers;
|
public IntPtr Buffers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the buffer structure version supported by this structure. Always 0.
|
||||||
|
/// </summary>
|
||||||
public const int ApiVersion = 0;
|
public const int ApiVersion = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,53 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes the type and purpose of a secure buffer passed to the native API.
|
||||||
|
/// </summary>
|
||||||
internal enum BufferType : int
|
internal enum BufferType : int
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer is empty.
|
||||||
|
/// </summary>
|
||||||
Empty = 0x00,
|
Empty = 0x00,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer contains message data. Message data can be plaintext or cipher text data.
|
||||||
|
/// </summary>
|
||||||
Data = 0x01,
|
Data = 0x01,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer contains opaque authentication token data.
|
||||||
|
/// </summary>
|
||||||
Token = 0x02,
|
Token = 0x02,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer contains parameters specific to the security package.
|
||||||
|
/// </summary>
|
||||||
Parameters = 0x03,
|
Parameters = 0x03,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer placeholder indicating that some data is missing.
|
||||||
|
/// </summary>
|
||||||
Missing = 0x04,
|
Missing = 0x04,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer passed to an API call contained more data than was necessary for completing the action,
|
||||||
|
/// such as the case when a streaming-mode connection that does not preserve message bounders, such as TCP
|
||||||
|
/// is used as the transport. The extra data is returned back to the caller in a buffer of this type.
|
||||||
|
/// </summary>
|
||||||
Extra = 0x05,
|
Extra = 0x05,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer contains a security data trailer, such as a message signature or marker, or framing data.
|
||||||
|
/// </summary>
|
||||||
Trailer = 0x06,
|
Trailer = 0x06,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer contains a security data header, such as a message signature, marker, or framing data.
|
||||||
|
/// </summary>
|
||||||
Header = 0x07,
|
Header = 0x07,
|
||||||
|
|
||||||
Padding = 0x09,
|
Padding = 0x09,
|
||||||
Stream = 0x0A,
|
Stream = 0x0A,
|
||||||
ChannelBindings = 0x0E,
|
ChannelBindings = 0x0E,
|
||||||
|
|||||||
@@ -60,7 +60,12 @@ namespace NSspi
|
|||||||
Unsupported = 0x80090302,
|
Unsupported = 0x80090302,
|
||||||
TargetUnknown = 0x80090303,
|
TargetUnknown = 0x80090303,
|
||||||
InternalError = 0x80090304,
|
InternalError = 0x80090304,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No security provider package was found with the given name.
|
||||||
|
/// </summary>
|
||||||
PackageNotFound = 0x80090305,
|
PackageNotFound = 0x80090305,
|
||||||
|
|
||||||
NotOwner = 0x80090306,
|
NotOwner = 0x80090306,
|
||||||
CannotInstall = 0x80090307,
|
CannotInstall = 0x80090307,
|
||||||
InvalidToken = 0x80090308,
|
InvalidToken = 0x80090308,
|
||||||
@@ -73,6 +78,18 @@ namespace NSspi
|
|||||||
MessageAltered = 0x8009030F,
|
MessageAltered = 0x8009030F,
|
||||||
OutOfSequence = 0x80090310,
|
OutOfSequence = 0x80090310,
|
||||||
NoAuthenticatingAuthority = 0x80090311,
|
NoAuthenticatingAuthority = 0x80090311,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer provided to an SSPI API call contained a message that was not complete.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This occurs regularly with SSPI contexts that exchange data using a streaming context,
|
||||||
|
/// where the data returned from the streaming communications channel, such as a TCP socket,
|
||||||
|
/// did not contain the complete message.
|
||||||
|
/// Similarly, a streaming channel may return too much data, in which case the API function
|
||||||
|
/// will indicate success, but will save off the extra, unrelated data in a buffer of
|
||||||
|
/// type 'extra'.
|
||||||
|
/// </remarks>
|
||||||
IncompleteMessage = 0x80090318,
|
IncompleteMessage = 0x80090318,
|
||||||
IncompleteCredentials = 0x80090320,
|
IncompleteCredentials = 0x80090320,
|
||||||
BufferNotEnough = 0x80090321,
|
BufferNotEnough = 0x80090321,
|
||||||
@@ -89,8 +106,16 @@ namespace NSspi
|
|||||||
BadBinding = 0x80090346
|
BadBinding = 0x80090346
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for the SecurityStatus enumeration.
|
||||||
|
/// </summary>
|
||||||
public static class SecurityStatusExtensions
|
public static class SecurityStatusExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether or not the status represents an error.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="status"></param>
|
||||||
|
/// <returns>True if the status represents an error condition.</returns>
|
||||||
public static bool IsError( this SecurityStatus status )
|
public static bool IsError( this SecurityStatus status )
|
||||||
{
|
{
|
||||||
return (uint)status > 0x80000000u;
|
return (uint)status > 0x80000000u;
|
||||||
|
|||||||
@@ -11,8 +11,9 @@ using NSspi.Contexts;
|
|||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents any SSPI handle created for credential handles, context handles, and security package
|
/// Represents the raw structure for any handle created for the SSPI API, for example, credential
|
||||||
/// handles. Any SSPI handle is always the size of two native pointers.
|
/// handles, context handles, and security package handles. Any SSPI handle is always the size
|
||||||
|
/// of two native pointers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The documentation for SSPI handles can be found here:
|
/// The documentation for SSPI handles can be found here:
|
||||||
@@ -21,8 +22,8 @@ namespace NSspi
|
|||||||
/// This class is not reference safe - if used directly, or referenced directly, it may be leaked,
|
/// This class is not reference safe - if used directly, or referenced directly, it may be leaked,
|
||||||
/// or subject to finalizer races, or any of the hundred of things SafeHandles were designed to fix.
|
/// or subject to finalizer races, or any of the hundred of things SafeHandles were designed to fix.
|
||||||
/// Do not directly use this class - use only though SafeHandle wrapper objects. Any reference needed
|
/// Do not directly use this class - use only though SafeHandle wrapper objects. Any reference needed
|
||||||
/// to this handle for performing work (InitializeSecurityContext, eg), should be done through
|
/// to this handle for performing work (InitializeSecurityContext, eg) should be performed a CER
|
||||||
/// a second class SafeSspiHandleReference so that reference counting is properly executed.
|
/// that employs handle reference counting across the native API invocation.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ]
|
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ]
|
||||||
internal struct RawSspiHandle
|
internal struct RawSspiHandle
|
||||||
@@ -30,12 +31,21 @@ namespace NSspi
|
|||||||
private IntPtr lowPart;
|
private IntPtr lowPart;
|
||||||
private IntPtr highPart;
|
private IntPtr highPart;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether or not the handle is set to the default, empty value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public bool IsZero()
|
public bool IsZero()
|
||||||
{
|
{
|
||||||
return this.lowPart == IntPtr.Zero && this.highPart == IntPtr.Zero;
|
return this.lowPart == IntPtr.Zero && this.highPart == IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This guy has to be executed in a CER.
|
/// <summary>
|
||||||
|
/// Sets the handle to an invalid value.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method is executed in a CER during handle release.
|
||||||
|
/// </remarks>
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
||||||
public void SetInvalid()
|
public void SetInvalid()
|
||||||
{
|
{
|
||||||
@@ -44,7 +54,9 @@ namespace NSspi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Safely encapsulates a raw handle used in the SSPI api.
|
||||||
|
/// </summary>
|
||||||
public abstract class SafeSspiHandle : SafeHandle
|
public abstract class SafeSspiHandle : SafeHandle
|
||||||
{
|
{
|
||||||
internal RawSspiHandle rawHandle;
|
internal RawSspiHandle rawHandle;
|
||||||
|
|||||||
@@ -7,19 +7,33 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Windows API Timestamp structure, which stores time in units of 100 nanosecond
|
||||||
|
/// ticks, counting from January 1st, year 1601 at 00:00 UTC. Time is stored as a 64-bit value.
|
||||||
|
/// </summary>
|
||||||
[StructLayout( LayoutKind.Sequential )]
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
public struct TimeStamp
|
public struct TimeStamp
|
||||||
{
|
{
|
||||||
public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the time value. Infinite times are often represented as values near, but not exactly
|
||||||
|
/// at the maximum signed 64-bit 2's complement value.
|
||||||
|
/// </summary>
|
||||||
private long time;
|
private long time;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the TimeStamp to an equivalant DateTime object. If the TimeStamp represents
|
||||||
|
/// a value larger than DateTime.MaxValue, then DateTime.MaxValue is returned.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public DateTime ToDateTime()
|
public DateTime ToDateTime()
|
||||||
{
|
{
|
||||||
ulong test = (ulong)this.time + (ulong)(Epoch.Ticks);
|
ulong test = (ulong)this.time + (ulong)(Epoch.Ticks);
|
||||||
|
|
||||||
// Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value
|
// Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value
|
||||||
// somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999.
|
// somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999.
|
||||||
|
// It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone
|
||||||
// http://stackoverflow.com/questions/24478056/
|
// http://stackoverflow.com/questions/24478056/
|
||||||
if ( test > (ulong)DateTime.MaxValue.Ticks )
|
if ( test > (ulong)DateTime.MaxValue.Ticks )
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user