Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bfa2f8ce4 | |||
|
|
3a7629fada | ||
|
|
0b81172157 | ||
|
|
d49e27109e | ||
|
|
b655f5650e | ||
|
|
2bc74ddb4f | ||
|
|
1a7f60d3e1 | ||
|
|
16bd8b2d68 | ||
|
|
06f1b08050 | ||
|
|
8c3126316f | ||
|
|
9cd6edbeb7 | ||
|
|
ad88537c14 | ||
|
|
2611d94033 | ||
|
|
f892e1c93f | ||
|
|
91f6a680cf | ||
|
|
52322afeaa | ||
|
|
002da1559b | ||
|
|
01ad97b272 | ||
|
|
ac4217d9d4 | ||
|
|
bbb7c7a060 | ||
|
|
4bd2ad0024 | ||
|
|
3ccdcc701e | ||
|
|
923d70195d | ||
|
|
56ca05b230 | ||
|
|
82eaae0570 | ||
|
|
6bf95f46ee | ||
|
|
5c63105acf | ||
|
|
19716405b8 | ||
|
|
f0820875c3 | ||
|
|
8355a6b821 | ||
|
|
4d79f1b5db | ||
|
|
aef74fe8aa | ||
|
|
37a7881d25 | ||
|
|
9350412fb6 | ||
|
|
6a5e6056a7 | ||
|
|
c6c0ac623e | ||
|
|
c07abdaa62 | ||
|
|
f2d4541bab | ||
|
|
0eb8ff49f2 | ||
|
|
3b189d2865 | ||
|
|
6ff68d8812 | ||
|
|
e631d77f01 | ||
|
|
4e629a71b2 | ||
|
|
8db4b6d8a5 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.vs
|
||||
/_ReSharper.Caches
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2014, Kevin Thompson
|
||||
Copyright (c) 2019, Kevin Thompson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 16.0.28527.54
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}"
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
@@ -13,7 +8,7 @@ namespace NSspi
|
||||
public static class ByteWriter
|
||||
{
|
||||
// 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>
|
||||
@@ -37,8 +32,7 @@ namespace NSspi
|
||||
buffer[position + 0] = (byte)( value >> 24 );
|
||||
buffer[position + 1] = (byte)( value >> 16 );
|
||||
buffer[position + 2] = (byte)( value >> 8 );
|
||||
buffer[position + 3] = (byte)( value);
|
||||
|
||||
buffer[position + 3] = (byte)( value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,4 +71,4 @@ namespace NSspi
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSspi.Buffers;
|
||||
using NSspi.Credentials;
|
||||
|
||||
@@ -14,7 +9,7 @@ namespace NSspi.Contexts
|
||||
/// with the server and to encrypt, decrypt, sign and verify messages to and from the server.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A client and server establish a shared security context by exchanging authentication tokens. Once
|
||||
/// A client and server establish a shared security context by exchanging authentication tokens. Once
|
||||
/// the shared context is established, the client and server can pass messages to each other, encrypted,
|
||||
/// signed, etc, using the established parameters of the shared context.
|
||||
/// </remarks>
|
||||
@@ -33,7 +28,7 @@ namespace NSspi.Contexts
|
||||
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the
|
||||
/// context once it is established. If a context cannot be established that satisfies the indicated
|
||||
/// properties, the context initialization is aborted.</param>
|
||||
public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib requestedAttribs )
|
||||
public ClientContext( Credential cred, string serverPrinc, ContextAttrib requestedAttribs )
|
||||
: base( cred )
|
||||
{
|
||||
this.serverPrinc = serverPrinc;
|
||||
@@ -47,11 +42,11 @@ namespace NSspi.Contexts
|
||||
/// This method is performed iteratively to start, continue, and end the authentication cycle with the
|
||||
/// server. Each stage works by acquiring a token from one side, presenting it to the other side
|
||||
/// which in turn may generate a new token.
|
||||
///
|
||||
///
|
||||
/// The cycle typically starts and ends with the client. On the first invocation on the client,
|
||||
/// no server token exists, and null is provided in its place. The client returns its status, providing
|
||||
/// its output token for the server. The server accepts the clients token as input and provides a
|
||||
/// token as output to send back to the client. This cycle continues until the server and client
|
||||
/// its output token for the server. The server accepts the clients token as input and provides a
|
||||
/// token as output to send back to the client. This cycle continues until the server and client
|
||||
/// both indicate, typically, a SecurityStatus of 'OK'.
|
||||
/// </remarks>
|
||||
/// <param name="serverToken">The most recently received token from the server, or null if beginning
|
||||
@@ -60,7 +55,7 @@ namespace NSspi.Contexts
|
||||
/// <returns>A status message indicating the progression of the authentication cycle.
|
||||
/// A status of 'OK' indicates that the cycle is complete, from the client's perspective. If the outToken
|
||||
/// is not null, it must be sent to the server.
|
||||
/// A status of 'Continue' indicates that the output token should be sent to the server and
|
||||
/// A status of 'Continue' indicates that the output token should be sent to the server and
|
||||
/// a response should be anticipated.</returns>
|
||||
public SecurityStatus Init( byte[] serverToken, out byte[] outToken )
|
||||
{
|
||||
@@ -73,7 +68,7 @@ namespace NSspi.Contexts
|
||||
|
||||
SecureBuffer serverBuffer;
|
||||
SecureBufferAdapter serverAdapter;
|
||||
|
||||
|
||||
if( this.Disposed )
|
||||
{
|
||||
throw new ObjectDisposedException( "ClientContext" );
|
||||
@@ -86,24 +81,24 @@ namespace NSspi.Contexts
|
||||
{
|
||||
throw new InvalidOperationException( "Must provide the server's response when continuing the init process." );
|
||||
}
|
||||
|
||||
|
||||
// The security package tells us how big its biggest token will be. We'll allocate a buffer
|
||||
// that size, and it'll tell us how much it used.
|
||||
outTokenBuffer = new SecureBuffer(
|
||||
new byte[ this.Credential.PackageInfo.MaxTokenLength ],
|
||||
BufferType.Token
|
||||
outTokenBuffer = new SecureBuffer(
|
||||
new byte[this.Credential.PackageInfo.MaxTokenLength],
|
||||
BufferType.Token
|
||||
);
|
||||
|
||||
serverBuffer = null;
|
||||
if ( serverToken != null )
|
||||
if( serverToken != null )
|
||||
{
|
||||
serverBuffer = new SecureBuffer( serverToken, BufferType.Token );
|
||||
}
|
||||
|
||||
// Some notes on handles and invoking InitializeSecurityContext
|
||||
// - The first time around, the phContext parameter (the 'old' handle) is a null pointer to what
|
||||
// would be an RawSspiHandle, to indicate this is the first time it's being called.
|
||||
// The phNewContext is a pointer (reference) to an RawSspiHandle struct of where to write the
|
||||
// - The first time around, the phContext parameter (the 'old' handle) is a null pointer to what
|
||||
// would be an RawSspiHandle, to indicate this is the first time it's being called.
|
||||
// The phNewContext is a pointer (reference) to an RawSspiHandle struct of where to write the
|
||||
// new handle's values.
|
||||
// - The next time you invoke ISC, it takes a pointer to the handle it gave you last time in phContext,
|
||||
// and takes a pointer to where it should write the new handle's values in phNewContext.
|
||||
@@ -111,13 +106,13 @@ namespace NSspi.Contexts
|
||||
// "On the second call, phNewContext can be the same as the handle specified in the phContext
|
||||
// parameter."
|
||||
// It will overwrite the handle you gave it with the new handle value.
|
||||
// - All handle structures themselves are actually *two* pointer variables, eg, 64 bits on 32-bit
|
||||
// - All handle structures themselves are actually *two* pointer variables, eg, 64 bits on 32-bit
|
||||
// Windows, 128 bits on 64-bit Windows.
|
||||
// - So in the end, on a 64-bit machine, we're passing a 64-bit value (the pointer to the struct) that
|
||||
// points to 128 bits of memory (the struct itself) for where to write the handle numbers.
|
||||
using ( outAdapter = new SecureBufferAdapter( outTokenBuffer ) )
|
||||
using( outAdapter = new SecureBufferAdapter( outTokenBuffer ) )
|
||||
{
|
||||
if ( this.ContextHandle.IsInvalid )
|
||||
if( this.ContextHandle.IsInvalid )
|
||||
{
|
||||
status = ContextNativeMethods.InitializeSecurityContext_1(
|
||||
ref this.Credential.Handle.rawHandle,
|
||||
@@ -136,7 +131,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
else
|
||||
{
|
||||
using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
|
||||
using( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
|
||||
{
|
||||
status = ContextNativeMethods.InitializeSecurityContext_2(
|
||||
ref this.Credential.Handle.rawHandle,
|
||||
@@ -179,4 +174,4 @@ namespace NSspi.Contexts
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Principal;
|
||||
using NSspi.Buffers;
|
||||
using NSspi.Contexts;
|
||||
using NSspi.Credentials;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a security context and provides common functionality required for all security
|
||||
/// Represents a security context and provides common functionality required for all security
|
||||
/// contexts.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class is abstract and has a protected constructor and Initialize method. The exact
|
||||
/// initialization implementation is provided by a subclasses, which may perform initialization
|
||||
/// This class is abstract and has a protected constructor and Initialize method. The exact
|
||||
/// initialization implementation is provided by a subclasses, which may perform initialization
|
||||
/// in a variety of manners.
|
||||
/// </remarks>
|
||||
public abstract class Context : IDisposable
|
||||
@@ -87,6 +83,11 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constant for wrapping only...no encryption
|
||||
/// </summary>
|
||||
protected uint KERB_WRAP_NO_ENCRYPT = 0x80000001;
|
||||
|
||||
/// <summary>
|
||||
/// Marks the context as having completed the initialization process, ie, exchanging of authentication tokens.
|
||||
/// </summary>
|
||||
@@ -122,6 +123,105 @@ namespace NSspi.Contexts
|
||||
this.Disposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the identity of the remote entity.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IIdentity GetRemoteIdentity()
|
||||
{
|
||||
IIdentity result = null;
|
||||
|
||||
using( var tokenHandle = GetContextToken() )
|
||||
{
|
||||
bool gotRef = false;
|
||||
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try
|
||||
{
|
||||
tokenHandle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch( Exception )
|
||||
{
|
||||
if( gotRef )
|
||||
{
|
||||
tokenHandle.DangerousRelease();
|
||||
gotRef = false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
result = new WindowsIdentity(
|
||||
tokenHandle.DangerousGetHandle(),
|
||||
this.Credential.SecurityPackage
|
||||
);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Make sure we release the handle, even if the allocation for
|
||||
// WindowsIdentity fails.
|
||||
tokenHandle.DangerousRelease();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private SafeTokenHandle GetContextToken()
|
||||
{
|
||||
bool gotRef = false;
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
SafeTokenHandle token;
|
||||
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try
|
||||
{
|
||||
this.ContextHandle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch( Exception )
|
||||
{
|
||||
if( gotRef )
|
||||
{
|
||||
this.ContextHandle.DangerousRelease();
|
||||
gotRef = false;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if( gotRef )
|
||||
{
|
||||
try
|
||||
{
|
||||
status = ContextNativeMethods.QuerySecurityContextToken(
|
||||
ref this.ContextHandle.rawHandle,
|
||||
out token
|
||||
);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.ContextHandle.DangerousRelease();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
token = null;
|
||||
}
|
||||
}
|
||||
|
||||
if( status != SecurityStatus.OK )
|
||||
{
|
||||
throw new SSPIException( "Failed to query context token.", status );
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts the byte array using the context's session key.
|
||||
/// </summary>
|
||||
@@ -135,8 +235,9 @@ namespace NSspi.Contexts
|
||||
/// - The padding buffer.
|
||||
/// </remarks>
|
||||
/// <param name="input">The raw message to encrypt.</param>
|
||||
/// <param name="wrapOnly">Only wrap the message, no encryption</param>
|
||||
/// <returns>The packed and encrypted message.</returns>
|
||||
public byte[] Encrypt( byte[] input )
|
||||
public byte[] Encrypt( byte[] input, bool wrapOnly = false )
|
||||
{
|
||||
// The message is encrypted in place in the buffer we provide to Win32 EncryptMessage
|
||||
SecPkgContext_Sizes sizes;
|
||||
@@ -161,9 +262,14 @@ namespace NSspi.Contexts
|
||||
|
||||
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
||||
{
|
||||
uint qualityOfProtection = 0u;
|
||||
if (wrapOnly)
|
||||
{
|
||||
qualityOfProtection = KERB_WRAP_NO_ENCRYPT;
|
||||
}
|
||||
status = ContextNativeMethods.SafeEncryptMessage(
|
||||
this.ContextHandle,
|
||||
0,
|
||||
qualityOfProtection,
|
||||
adapter,
|
||||
0
|
||||
);
|
||||
@@ -200,7 +306,7 @@ namespace NSspi.Contexts
|
||||
|
||||
Array.Copy( paddingBuffer.Buffer, 0, result, position, paddingBuffer.Length );
|
||||
position += paddingBuffer.Length;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -217,8 +323,9 @@ namespace NSspi.Contexts
|
||||
/// - The padding buffer.
|
||||
/// </remarks>
|
||||
/// <param name="input">The packed and encrypted data.</param>
|
||||
/// <param name="unwrapOnly">Only wrap the message, no encryption</param>
|
||||
/// <returns>The original plaintext message.</returns>
|
||||
public byte[] Decrypt( byte[] input )
|
||||
public byte[] Decrypt( byte[] input, bool unwrapOnly = false)
|
||||
{
|
||||
SecPkgContext_Sizes sizes;
|
||||
|
||||
@@ -257,7 +364,7 @@ namespace NSspi.Contexts
|
||||
paddingLength = ByteWriter.ReadInt16_BE( input, position );
|
||||
position += 2;
|
||||
|
||||
if ( trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length )
|
||||
if( trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length )
|
||||
{
|
||||
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
|
||||
}
|
||||
@@ -278,7 +385,7 @@ namespace NSspi.Contexts
|
||||
{
|
||||
throw new ArgumentException( "Input is missing data - it is not long enough to contain a fully encrypted message" );
|
||||
}
|
||||
|
||||
|
||||
if( dataBuffer.Length <= remaining )
|
||||
{
|
||||
Array.Copy( input, position, dataBuffer.Buffer, 0, dataBuffer.Length );
|
||||
@@ -295,13 +402,17 @@ namespace NSspi.Contexts
|
||||
Array.Copy( input, position, paddingBuffer.Buffer, 0, paddingBuffer.Length );
|
||||
}
|
||||
// else there was no padding.
|
||||
|
||||
|
||||
using( adapter = new SecureBufferAdapter( new [] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
||||
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
||||
{
|
||||
uint qualityOfProtection = 0u;
|
||||
if (unwrapOnly)
|
||||
{
|
||||
qualityOfProtection = KERB_WRAP_NO_ENCRYPT;
|
||||
}
|
||||
status = ContextNativeMethods.SafeDecryptMessage(
|
||||
this.ContextHandle,
|
||||
0,
|
||||
qualityOfProtection,
|
||||
adapter,
|
||||
0
|
||||
);
|
||||
@@ -348,7 +459,7 @@ namespace NSspi.Contexts
|
||||
|
||||
Array.Copy( message, dataBuffer.Buffer, message.Length );
|
||||
|
||||
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
||||
using( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
||||
{
|
||||
status = ContextNativeMethods.SafeMakeSignature(
|
||||
this.ContextHandle,
|
||||
@@ -358,7 +469,7 @@ namespace NSspi.Contexts
|
||||
);
|
||||
}
|
||||
|
||||
if ( status != SecurityStatus.OK )
|
||||
if( status != SecurityStatus.OK )
|
||||
{
|
||||
throw new SSPIException( "Failed to create message signature.", status );
|
||||
}
|
||||
@@ -366,7 +477,7 @@ namespace NSspi.Contexts
|
||||
byte[] outMessage;
|
||||
int position = 0;
|
||||
|
||||
// Enough room for
|
||||
// Enough room for
|
||||
// - original message length (4 bytes)
|
||||
// - signature length (2 bytes)
|
||||
// - original message
|
||||
@@ -389,6 +500,35 @@ namespace NSspi.Contexts
|
||||
return outMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Session Key from a context or null on failure.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Session keys are sometimes needed for other purposes or HMAC functions. This function
|
||||
/// will run QueryAttribute to get the session key struct, and read and return the key from
|
||||
/// that struct.
|
||||
/// </remarks>
|
||||
/// <returns>byte[] with the session key data or null on failure</returns>
|
||||
public byte[] QuerySessionKey()
|
||||
{
|
||||
SecurityStatus status;
|
||||
|
||||
byte[] SessionKey = null;
|
||||
|
||||
status = ContextNativeMethods.SafeQueryContextAttribute(
|
||||
this.ContextHandle,
|
||||
ContextQueryAttrib.SessionKey,
|
||||
ref SessionKey
|
||||
);
|
||||
|
||||
if( status != SecurityStatus.OK )
|
||||
{
|
||||
throw new SSPIException( "Failed to query session key.", status );
|
||||
}
|
||||
|
||||
return SessionKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature of a signed message
|
||||
/// </summary>
|
||||
@@ -414,8 +554,8 @@ namespace NSspi.Contexts
|
||||
CheckLifecycle();
|
||||
|
||||
sizes = QueryBufferSizes();
|
||||
|
||||
if ( signedMessage.Length < 2 + 4 + sizes.MaxSignature )
|
||||
|
||||
if( signedMessage.Length < 2 + 4 + sizes.MaxSignature )
|
||||
{
|
||||
throw new ArgumentException( "Input message is too small to possibly fit a valid message" );
|
||||
}
|
||||
@@ -430,7 +570,7 @@ namespace NSspi.Contexts
|
||||
sigLen = ByteWriter.ReadInt16_BE( signedMessage, position );
|
||||
position += 2;
|
||||
|
||||
if ( messageLen + sigLen + 2 + 4 > signedMessage.Length )
|
||||
if( messageLen + sigLen + 2 + 4 > signedMessage.Length )
|
||||
{
|
||||
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
|
||||
}
|
||||
@@ -443,7 +583,7 @@ namespace NSspi.Contexts
|
||||
Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen );
|
||||
position += sigLen;
|
||||
|
||||
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
||||
using( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
||||
{
|
||||
status = ContextNativeMethods.SafeVerifySignature(
|
||||
this.ContextHandle,
|
||||
@@ -453,12 +593,12 @@ namespace NSspi.Contexts
|
||||
);
|
||||
}
|
||||
|
||||
if ( status == SecurityStatus.OK )
|
||||
if( status == SecurityStatus.OK )
|
||||
{
|
||||
origMessage = dataBuffer.Buffer;
|
||||
return true;
|
||||
}
|
||||
else if ( status == SecurityStatus.MessageAltered ||
|
||||
else if( status == SecurityStatus.MessageAltered ||
|
||||
status == SecurityStatus.OutOfSequence )
|
||||
{
|
||||
origMessage = null;
|
||||
@@ -485,9 +625,9 @@ namespace NSspi.Contexts
|
||||
{
|
||||
this.ContextHandle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch ( Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
this.ContextHandle.DangerousRelease();
|
||||
gotRef = false;
|
||||
@@ -497,7 +637,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
status = ContextNativeMethods.QueryContextAttributes_Sizes(
|
||||
ref this.ContextHandle.rawHandle,
|
||||
@@ -521,7 +661,7 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
/// <param name="attrib">The string-valued attribute to query.</param>
|
||||
/// <returns></returns>
|
||||
private string QueryContextString(ContextQueryAttrib attrib)
|
||||
private string QueryContextString( ContextQueryAttrib attrib )
|
||||
{
|
||||
SecPkgContext_String stringAttrib;
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
@@ -540,9 +680,9 @@ namespace NSspi.Contexts
|
||||
{
|
||||
this.ContextHandle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch ( Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
this.ContextHandle.DangerousRelease();
|
||||
gotRef = false;
|
||||
@@ -551,7 +691,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
status = ContextNativeMethods.QueryContextAttributes_String(
|
||||
ref this.ContextHandle.rawHandle,
|
||||
@@ -561,14 +701,14 @@ namespace NSspi.Contexts
|
||||
|
||||
this.ContextHandle.DangerousRelease();
|
||||
|
||||
if ( status == SecurityStatus.OK )
|
||||
if( status == SecurityStatus.OK )
|
||||
{
|
||||
result = Marshal.PtrToStringUni( stringAttrib.StringResult );
|
||||
ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( status == SecurityStatus.Unsupported )
|
||||
{
|
||||
return null;
|
||||
@@ -582,7 +722,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the object's lifecycle (initialization / disposition) state is suitable for using the
|
||||
/// Verifies that the object's lifecycle (initialization / disposition) state is suitable for using the
|
||||
/// object.
|
||||
/// </summary>
|
||||
private void CheckLifecycle()
|
||||
@@ -597,4 +737,4 @@ namespace NSspi.Contexts
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines options for creating a security context via win32 InitializeSecurityContext
|
||||
/// Defines options for creating a security context via win32 InitializeSecurityContext
|
||||
/// (used by clients) and AcceptSecurityContext (used by servers).
|
||||
/// Required attribute flags are specified when creating the context. InitializeSecurityContext
|
||||
/// and AcceptSecurityContext returns a value indicating what final attributes the created context
|
||||
/// and AcceptSecurityContext returns a value indicating what final attributes the created context
|
||||
/// actually has.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ContextAttrib : int
|
||||
public enum ContextAttrib : int
|
||||
{
|
||||
/// <summary>
|
||||
/// No additional attributes are provided.
|
||||
/// </summary>
|
||||
Zero = 0,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The server can use the context to authenticate to other servers as the client. The
|
||||
/// MutualAuth flag must be set for this flag to work. Valid for Kerberos. Ignore this flag for
|
||||
/// MutualAuth flag must be set for this flag to work. Valid for Kerberos. Ignore this flag for
|
||||
/// constrained delegation.
|
||||
/// </summary>
|
||||
Delegate = 0x00000001,
|
||||
@@ -36,17 +32,16 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
MutualAuth = 0x00000002,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature
|
||||
/// Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature
|
||||
/// message support functionality.
|
||||
/// </summary>
|
||||
ReplayDetect = 0x00000004,
|
||||
|
||||
/// <summary>
|
||||
/// Detect messages received out of sequence when using the message support functionality.
|
||||
/// This flag implies all of the conditions specified by the Integrity flag - out-of-order sequence
|
||||
/// detection can only be trusted if the integrity of any underlying sequence detection mechanism
|
||||
/// Detect messages received out of sequence when using the message support functionality.
|
||||
/// This flag implies all of the conditions specified by the Integrity flag - out-of-order sequence
|
||||
/// detection can only be trusted if the integrity of any underlying sequence detection mechanism
|
||||
/// in transmitted data can be trusted.
|
||||
/// </summary>
|
||||
SequenceDetect = 0x00000008,
|
||||
@@ -55,12 +50,12 @@ namespace NSspi.Contexts
|
||||
// Confidentiality is supported for NTLM with Microsoft
|
||||
// Windows NT version 4.0, SP4 and later and with the
|
||||
// Kerberos protocol in Microsoft Windows 2000 and later.
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The context must protect data while in transit. Encrypt messages by using the EncryptMessage function.
|
||||
/// </summary>
|
||||
Confidentiality = 0x00000010,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A new session key must be negotiated.
|
||||
/// This value is supported only by the Kerberos security package.
|
||||
@@ -68,13 +63,13 @@ namespace NSspi.Contexts
|
||||
UseSessionKey = 0x00000020,
|
||||
|
||||
/// <summary>
|
||||
/// The security package allocates output buffers for you. Buffers allocated by the security package have
|
||||
/// The security package allocates output buffers for you. Buffers allocated by the security package have
|
||||
/// to be released by the context memory management functions.
|
||||
/// </summary>
|
||||
AllocateMemory = 0x00000100,
|
||||
|
||||
/// <summary>
|
||||
/// The security context will not handle formatting messages. This value is the default for the Kerberos,
|
||||
/// The security context will not handle formatting messages. This value is the default for the Kerberos,
|
||||
/// Negotiate, and NTLM security packages.
|
||||
/// </summary>
|
||||
Connection = 0x00000800,
|
||||
@@ -84,7 +79,7 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A client specifies InitExtendedError in InitializeSecurityContext
|
||||
/// and the server specifies AcceptExtendedError in AcceptSecurityContext.
|
||||
/// and the server specifies AcceptExtendedError in AcceptSecurityContext.
|
||||
/// </remarks>
|
||||
InitExtendedError = 0x00004000,
|
||||
|
||||
@@ -93,7 +88,7 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A client specifies InitExtendedError in InitializeSecurityContext
|
||||
/// and the server specifies AcceptExtendedError in AcceptSecurityContext.
|
||||
/// and the server specifies AcceptExtendedError in AcceptSecurityContext.
|
||||
/// </remarks>
|
||||
AcceptExtendedError = 0x00008000,
|
||||
|
||||
@@ -112,7 +107,7 @@ namespace NSspi.Contexts
|
||||
/// Replayed and out-of-sequence messages will not be detected with the setting of this attribute.
|
||||
/// Set ReplayDetect and SequenceDetect also if these behaviors are desired.
|
||||
/// </summary>
|
||||
InitIntegrity = 0x00010000,
|
||||
InitIntegrity = 0x00010000,
|
||||
|
||||
/// <summary>
|
||||
/// Sign messages and verify signatures by using the EncryptMessage and MakeSignature functions.
|
||||
@@ -121,7 +116,16 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
AcceptIntegrity = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Set by a client; indicates the context can only impersonate with limited privileges,
|
||||
/// allowing the server only to identify the client when impersonating.
|
||||
/// </summary>
|
||||
InitIdentify = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// Set by a server; indicates the context can only impersonate with limited privileges,
|
||||
/// allowing the server only to identify the client when impersonating.
|
||||
/// </summary>
|
||||
AcceptIdentify = 0x00080000,
|
||||
|
||||
/// <summary>
|
||||
@@ -134,4 +138,4 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
InitUseSuppliedCreds = 0x00000080,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSspi.Buffers;
|
||||
using NSspi.Contexts;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
@@ -28,7 +23,7 @@ namespace NSspi.Contexts
|
||||
_Out_ PULONG pfContextAttr,
|
||||
_Out_opt_ PTimeStamp ptsTimeStamp
|
||||
);
|
||||
|
||||
|
||||
SECURITY_STATUS SEC_Entry InitializeSecurityContext(
|
||||
_In_opt_ PCredHandle phCredential, // [in] handle to the credentials
|
||||
_In_opt_ PCtxtHandle phContext, // [in/out] handle of partially formed context. Always NULL the first time through
|
||||
@@ -45,7 +40,7 @@ namespace NSspi.Contexts
|
||||
);
|
||||
*/
|
||||
|
||||
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext",CharSet = CharSet.Unicode )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus AcceptSecurityContext_1(
|
||||
ref RawSspiHandle credHandle,
|
||||
IntPtr oldContextHandle,
|
||||
@@ -58,7 +53,6 @@ namespace NSspi.Contexts
|
||||
ref TimeStamp expiry
|
||||
);
|
||||
|
||||
|
||||
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus AcceptSecurityContext_2(
|
||||
ref RawSspiHandle credHandle,
|
||||
@@ -72,7 +66,6 @@ namespace NSspi.Contexts
|
||||
ref TimeStamp expiry
|
||||
);
|
||||
|
||||
|
||||
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus InitializeSecurityContext_1(
|
||||
ref RawSspiHandle credentialHandle,
|
||||
@@ -89,7 +82,6 @@ namespace NSspi.Contexts
|
||||
ref TimeStamp expiry
|
||||
);
|
||||
|
||||
|
||||
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus InitializeSecurityContext_2(
|
||||
ref RawSspiHandle credentialHandle,
|
||||
@@ -106,18 +98,17 @@ namespace NSspi.Contexts
|
||||
ref TimeStamp expiry
|
||||
);
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle );
|
||||
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus EncryptMessage(
|
||||
ref RawSspiHandle contextHandle,
|
||||
int qualityOfProtection,
|
||||
uint qualityOfProtection,
|
||||
IntPtr bufferDescriptor,
|
||||
int sequenceNumber
|
||||
uint sequenceNumber
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
@@ -125,17 +116,17 @@ namespace NSspi.Contexts
|
||||
internal static extern SecurityStatus DecryptMessage(
|
||||
ref RawSspiHandle contextHandle,
|
||||
IntPtr bufferDescriptor,
|
||||
int sequenceNumber,
|
||||
int qualityOfProtection
|
||||
uint sequenceNumber,
|
||||
uint qualityOfProtection
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "MakeSignature", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus MakeSignature(
|
||||
ref RawSspiHandle contextHandle,
|
||||
int qualityOfProtection,
|
||||
uint qualityOfProtection,
|
||||
IntPtr bufferDescriptor,
|
||||
int sequenceNumber
|
||||
uint sequenceNumber
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
@@ -143,8 +134,8 @@ namespace NSspi.Contexts
|
||||
internal static extern SecurityStatus VerifySignature(
|
||||
ref RawSspiHandle contextHandle,
|
||||
IntPtr bufferDescriptor,
|
||||
int sequenceNumber,
|
||||
int qualityOfProtection
|
||||
uint sequenceNumber,
|
||||
uint qualityOfProtection
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
@@ -155,7 +146,7 @@ namespace NSspi.Contexts
|
||||
ref SecPkgContext_Sizes sizes
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus QueryContextAttributes_String(
|
||||
ref RawSspiHandle contextHandle,
|
||||
@@ -163,11 +154,18 @@ namespace NSspi.Contexts
|
||||
ref SecPkgContext_String names
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus QueryContextAttributes(
|
||||
ref RawSspiHandle contextHandle,
|
||||
ContextQueryAttrib attrib,
|
||||
IntPtr attribute
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle );
|
||||
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle );
|
||||
@@ -176,8 +174,78 @@ namespace NSspi.Contexts
|
||||
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityContextToken", SetLastError = true )]
|
||||
internal static extern SecurityStatus QuerySecurityContextToken( ref RawSspiHandle contextHandle, [Out] out SafeTokenHandle handle );
|
||||
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
private class KeyStruct
|
||||
{
|
||||
public int size;
|
||||
public IntPtr data;
|
||||
}
|
||||
|
||||
internal static SecurityStatus SafeQueryContextAttribute(
|
||||
SafeContextHandle handle,
|
||||
ContextQueryAttrib attribute,
|
||||
ref byte[] buffer
|
||||
)
|
||||
{
|
||||
bool gotRef = false;
|
||||
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
|
||||
int pointerSize = System.Environment.Is64BitOperatingSystem ? 8 : 4; //NOTE: update this when 128 bit processors exist
|
||||
IntPtr alloc_buffer = Marshal.AllocHGlobal( sizeof( uint ) + pointerSize ); //NOTE: this is at most 4 + sizeof(void*) bytes
|
||||
//see struct SecPkgContext_SessionKey
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380096(v=vs.85).aspx
|
||||
try
|
||||
{
|
||||
handle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch( Exception )
|
||||
{
|
||||
if( gotRef )
|
||||
{
|
||||
handle.DangerousRelease();
|
||||
gotRef = false;
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if( gotRef )
|
||||
{
|
||||
status = ContextNativeMethods.QueryContextAttributes(
|
||||
ref handle.rawHandle,
|
||||
attribute,
|
||||
alloc_buffer
|
||||
);
|
||||
if( status == SecurityStatus.OK )
|
||||
{
|
||||
KeyStruct key = new KeyStruct();
|
||||
|
||||
Marshal.PtrToStructure( alloc_buffer, key ); // fit to the proper size, read a byte[]
|
||||
|
||||
byte[] sizedBuffer = new byte[key.size];
|
||||
|
||||
for( int i = 0; i < key.size; i++ )
|
||||
sizedBuffer[i] = Marshal.ReadByte( key.data, i );
|
||||
|
||||
buffer = sizedBuffer;
|
||||
}
|
||||
handle.DangerousRelease();
|
||||
}
|
||||
}
|
||||
Marshal.FreeHGlobal( alloc_buffer );
|
||||
return status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
|
||||
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
|
||||
/// performed in a proper CER.
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
@@ -187,9 +255,9 @@ namespace NSspi.Contexts
|
||||
/// <returns></returns>
|
||||
internal static SecurityStatus SafeEncryptMessage(
|
||||
SafeContextHandle handle,
|
||||
int qualityOfProtection,
|
||||
uint qualityOfProtection,
|
||||
SecureBufferAdapter bufferAdapter,
|
||||
int sequenceNumber )
|
||||
uint sequenceNumber )
|
||||
{
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
bool gotRef = false;
|
||||
@@ -199,9 +267,9 @@ namespace NSspi.Contexts
|
||||
{
|
||||
handle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch ( Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
handle.DangerousRelease();
|
||||
gotRef = false;
|
||||
@@ -211,7 +279,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
status = ContextNativeMethods.EncryptMessage(
|
||||
ref handle.rawHandle,
|
||||
@@ -228,7 +296,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely invokes the native DecryptMessage function, making sure that handle ref counting is
|
||||
/// Safely invokes the native DecryptMessage function, making sure that handle ref counting is
|
||||
/// performed in a proper CER.
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
@@ -236,11 +304,11 @@ namespace NSspi.Contexts
|
||||
/// <param name="bufferAdapter"></param>
|
||||
/// <param name="sequenceNumber"></param>
|
||||
/// <returns></returns>
|
||||
internal static SecurityStatus SafeDecryptMessage(
|
||||
SafeContextHandle handle,
|
||||
int qualityOfProtection,
|
||||
SecureBufferAdapter bufferAdapter,
|
||||
int sequenceNumber )
|
||||
internal static SecurityStatus SafeDecryptMessage(
|
||||
SafeContextHandle handle,
|
||||
uint qualityOfProtection,
|
||||
SecureBufferAdapter bufferAdapter,
|
||||
uint sequenceNumber )
|
||||
{
|
||||
SecurityStatus status = SecurityStatus.InvalidHandle;
|
||||
bool gotRef = false;
|
||||
@@ -279,7 +347,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely invokes the native MakeSignature function, making sure that handle ref counting is
|
||||
/// Safely invokes the native MakeSignature function, making sure that handle ref counting is
|
||||
/// performed in a proper CER.
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
@@ -289,9 +357,9 @@ namespace NSspi.Contexts
|
||||
/// <returns></returns>
|
||||
internal static SecurityStatus SafeMakeSignature(
|
||||
SafeContextHandle handle,
|
||||
int qualityOfProtection,
|
||||
uint qualityOfProtection,
|
||||
SecureBufferAdapter adapter,
|
||||
int sequenceNumber )
|
||||
uint sequenceNumber )
|
||||
{
|
||||
bool gotRef = false;
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
@@ -301,9 +369,9 @@ namespace NSspi.Contexts
|
||||
{
|
||||
handle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch ( Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
handle.DangerousRelease();
|
||||
gotRef = false;
|
||||
@@ -313,7 +381,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
status = ContextNativeMethods.MakeSignature(
|
||||
ref handle.rawHandle,
|
||||
@@ -330,7 +398,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely invokes the native VerifySignature function, making sure that handle ref counting is
|
||||
/// Safely invokes the native VerifySignature function, making sure that handle ref counting is
|
||||
/// performed in a proper CER.
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
@@ -340,9 +408,9 @@ namespace NSspi.Contexts
|
||||
/// <returns></returns>
|
||||
internal static SecurityStatus SafeVerifySignature(
|
||||
SafeContextHandle handle,
|
||||
int qualityOfProtection,
|
||||
uint qualityOfProtection,
|
||||
SecureBufferAdapter adapter,
|
||||
int sequenceNumber )
|
||||
uint sequenceNumber )
|
||||
{
|
||||
bool gotRef = false;
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
@@ -352,9 +420,9 @@ namespace NSspi.Contexts
|
||||
{
|
||||
handle.DangerousAddRef( ref gotRef );
|
||||
}
|
||||
catch ( Exception )
|
||||
catch( Exception )
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
handle.DangerousRelease();
|
||||
gotRef = false;
|
||||
@@ -364,7 +432,7 @@ namespace NSspi.Contexts
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( gotRef )
|
||||
if( gotRef )
|
||||
{
|
||||
status = ContextNativeMethods.VerifySignature(
|
||||
ref handle.rawHandle,
|
||||
@@ -380,4 +448,4 @@ namespace NSspi.Contexts
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
@@ -27,4 +23,4 @@ namespace NSspi.Contexts
|
||||
{
|
||||
public IntPtr StringResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
@@ -36,5 +32,15 @@ namespace NSspi.Contexts
|
||||
/// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
|
||||
/// </remarks>
|
||||
Authority = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Queries the context for it's neogtiated SessionKey
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Results for a query of this type are stored in a Win32 SecPkgContext_SessionKey structure
|
||||
/// </remarks>
|
||||
SessionKey = 9,
|
||||
|
||||
AccessToken = 13, //not implemented yet but this would be cool
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents impersonation performed on a server on behalf of a client.
|
||||
/// Represents impersonation performed on a server on behalf of a client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The handle controls the lifetime of impersonation, and will revert the impersonation
|
||||
/// if it is disposed, or if it is finalized ie by being leaked and garbage collected.
|
||||
///
|
||||
///
|
||||
/// If the handle is accidentally leaked while operations are performed on behalf of the user,
|
||||
/// impersonation may be reverted at any arbitrary time, perhaps during those operations.
|
||||
/// This may lead to operations being performed in the security context of the server,
|
||||
/// This may lead to operations being performed in the security context of the server,
|
||||
/// potentially leading to security vulnerabilities.
|
||||
/// </remarks>
|
||||
public class ImpersonationHandle : IDisposable
|
||||
{
|
||||
private readonly ServerContext server;
|
||||
|
||||
private bool disposed;
|
||||
private ServerContext server;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
|
||||
/// </summary>
|
||||
/// <param name="server">The server context that is performing impersonation.</param>
|
||||
internal ImpersonationHandle(ServerContext server)
|
||||
internal ImpersonationHandle( ServerContext server )
|
||||
{
|
||||
this.server = server;
|
||||
this.disposed = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes the ImpersonationHandle by reverting the impersonation.
|
||||
/// </summary>
|
||||
~ImpersonationHandle()
|
||||
{
|
||||
Dispose( false );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverts the impersonation.
|
||||
/// Reverts impersonation.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -47,13 +49,28 @@ namespace NSspi.Contexts
|
||||
GC.SuppressFinalize( this );
|
||||
}
|
||||
|
||||
protected virtual void Dispose( bool disposing )
|
||||
/// <summary>
|
||||
/// Reverts impersonation.
|
||||
/// </summary>
|
||||
/// <param name="disposing">True if being disposed, false if being finalized.</param>
|
||||
private void Dispose( bool disposing )
|
||||
{
|
||||
if( disposing && this.disposed == false && this.server != null && this.server.Disposed == false )
|
||||
// This implements a variant of the typical dispose pattern. Always try to revert
|
||||
// impersonation, even if finalizing. Don't do anything if we're already reverted.
|
||||
|
||||
if( this.disposed == false )
|
||||
{
|
||||
this.server.RevertImpersonate();
|
||||
this.disposed = true;
|
||||
|
||||
// Just in case the reference is being pulled out from under us, pull a stable copy
|
||||
// of the reference while we're null-checking.
|
||||
var serverCopy = this.server;
|
||||
|
||||
if( serverCopy != null && serverCopy.Disposed == false )
|
||||
{
|
||||
serverCopy.RevertImpersonate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
@@ -12,10 +8,17 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
public class SafeContextHandle : SafeSspiHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeContextHandle"/> class.
|
||||
/// </summary>
|
||||
public SafeContextHandle()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Releases the safe context handle.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
@@ -28,4 +31,4 @@ namespace NSspi.Contexts
|
||||
return status == SecurityStatus.OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
NSspi/Contexts/SafeTokenHandle.cs
Normal file
27
NSspi/Contexts/SafeTokenHandle.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NSspi.Contexts
|
||||
{
|
||||
public class SafeTokenHandle : SafeHandle
|
||||
{
|
||||
public SafeTokenHandle() : base( IntPtr.Zero, true )
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get
|
||||
{
|
||||
return handle == IntPtr.Zero || handle == new IntPtr( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
NativeMethods.CloseHandle( this.handle );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using NSspi.Buffers;
|
||||
using NSspi.Credentials;
|
||||
|
||||
@@ -14,24 +12,31 @@ namespace NSspi.Contexts
|
||||
/// </summary>
|
||||
public class ServerContext : Context
|
||||
{
|
||||
private ContextAttrib requestedAttribs;
|
||||
private ContextAttrib finalAttribs;
|
||||
private readonly ContextAttrib requestedAttribs;
|
||||
private readonly bool impersonationSetsThreadPrinciple;
|
||||
|
||||
private ContextAttrib finalAttribs;
|
||||
private bool impersonating;
|
||||
|
||||
/// <summary>
|
||||
/// Performs basic initialization of a new instance of the ServerContext class. The ServerContext
|
||||
/// is not ready for message manipulation until a security context has been established with a client.
|
||||
/// Performs basic initialization of a new instance of the ServerContext class. The
|
||||
/// ServerContext is not ready for message manipulation until a security context has been
|
||||
/// established with a client.
|
||||
/// </summary>
|
||||
/// <param name="cred"></param>
|
||||
/// <param name="requestedAttribs"></param>
|
||||
public ServerContext(ServerCredential cred, ContextAttrib requestedAttribs) : base ( cred )
|
||||
/// <param name="impersonationSetsThreadPrinciple">
|
||||
/// If true, the `Thread.CurrentPrinciple` property will be modified by successful impersonation.
|
||||
/// </param>
|
||||
public ServerContext( Credential cred, ContextAttrib requestedAttribs, bool impersonationSetsThreadPrinciple = false ) : base( cred )
|
||||
{
|
||||
this.requestedAttribs = requestedAttribs;
|
||||
this.impersonationSetsThreadPrinciple = impersonationSetsThreadPrinciple;
|
||||
|
||||
this.finalAttribs = ContextAttrib.Zero;
|
||||
|
||||
this.impersonating = false;
|
||||
|
||||
|
||||
this.SupportsImpersonate = this.Credential.PackageInfo.Capabilities.HasFlag( SecPkgCapability.Impersonation );
|
||||
}
|
||||
|
||||
@@ -50,11 +55,11 @@ namespace NSspi.Contexts
|
||||
/// This method is performed iteratively to continue and end the authentication cycle with the
|
||||
/// client. Each stage works by acquiring a token from one side, presenting it to the other side
|
||||
/// which in turn may generate a new token.
|
||||
///
|
||||
///
|
||||
/// The cycle typically starts and ends with the client. On the first invocation on the client,
|
||||
/// no server token exists, and null is provided in its place. The client returns its status, providing
|
||||
/// its output token for the server. The server accepts the clients token as input and provides a
|
||||
/// token as output to send back to the client. This cycle continues until the server and client
|
||||
/// its output token for the server. The server accepts the clients token as input and provides a
|
||||
/// token as output to send back to the client. This cycle continues until the server and client
|
||||
/// both indicate, typically, a SecurityStatus of 'OK'.
|
||||
/// </remarks>
|
||||
/// <param name="clientToken">The most recently received token from the client.</param>
|
||||
@@ -63,7 +68,7 @@ namespace NSspi.Contexts
|
||||
/// <returns>A status message indicating the progression of the authentication cycle.
|
||||
/// A status of 'OK' indicates that the cycle is complete, from the servers's perspective. If the nextToken
|
||||
/// is not null, it must be sent to the client.
|
||||
/// A status of 'Continue' indicates that the output token should be sent to the client and
|
||||
/// A status of 'Continue' indicates that the output token should be sent to the client and
|
||||
/// a response should be anticipated.</returns>
|
||||
public SecurityStatus AcceptToken( byte[] clientToken, out byte[] nextToken )
|
||||
{
|
||||
@@ -82,21 +87,21 @@ namespace NSspi.Contexts
|
||||
}
|
||||
else if( this.Initialized )
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
throw new InvalidOperationException(
|
||||
"Attempted to continue initialization of a ServerContext after initialization had completed."
|
||||
);
|
||||
}
|
||||
|
||||
clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
|
||||
|
||||
outBuffer = new SecureBuffer(
|
||||
new byte[ this.Credential.PackageInfo.MaxTokenLength ],
|
||||
BufferType.Token
|
||||
outBuffer = new SecureBuffer(
|
||||
new byte[this.Credential.PackageInfo.MaxTokenLength],
|
||||
BufferType.Token
|
||||
);
|
||||
|
||||
using ( clientAdapter = new SecureBufferAdapter( clientBuffer ) )
|
||||
using( clientAdapter = new SecureBufferAdapter( clientBuffer ) )
|
||||
{
|
||||
using ( outAdapter = new SecureBufferAdapter( outBuffer ) )
|
||||
using( outAdapter = new SecureBufferAdapter( outBuffer ) )
|
||||
{
|
||||
if( this.ContextHandle.IsInvalid )
|
||||
{
|
||||
@@ -125,19 +130,15 @@ namespace NSspi.Contexts
|
||||
ref this.finalAttribs,
|
||||
ref rawExpiry
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( status == SecurityStatus.OK )
|
||||
if( status == SecurityStatus.OK )
|
||||
{
|
||||
nextToken = null;
|
||||
|
||||
base.Initialize( rawExpiry.ToDateTime() );
|
||||
|
||||
if ( outBuffer.Length != 0 )
|
||||
if( outBuffer.Length != 0 )
|
||||
{
|
||||
nextToken = new byte[outBuffer.Length];
|
||||
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
|
||||
@@ -147,7 +148,7 @@ namespace NSspi.Contexts
|
||||
nextToken = null;
|
||||
}
|
||||
}
|
||||
else if ( status == SecurityStatus.ContinueNeeded )
|
||||
else if( status == SecurityStatus.ContinueNeeded )
|
||||
{
|
||||
nextToken = new byte[outBuffer.Length];
|
||||
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
|
||||
@@ -161,17 +162,17 @@ namespace NSspi.Contexts
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the current thread's security context to impersonate the user of the client.
|
||||
/// Changes the current thread's security context to impersonate the user of the client.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Requires that the security package provided with the server's credentials, as well as the
|
||||
/// Requires that the security package provided with the server's credentials, as well as the
|
||||
/// client's credentials, support impersonation.
|
||||
///
|
||||
/// Currently, only one thread may initiate impersonation per security context. Impersonation may
|
||||
///
|
||||
/// Currently, only one thread may initiate impersonation per security context. Impersonation may
|
||||
/// follow threads created by the initial impersonation thread, however.
|
||||
/// </remarks>
|
||||
/// <returns>A handle to capture the lifetime of the impersonation. Dispose the handle to revert
|
||||
/// impersonation. If the handle is leaked, the impersonation will automatically revert at a
|
||||
/// impersonation. If the handle is leaked, the impersonation will automatically revert at a
|
||||
/// non-deterministic time when the handle is finalized by the Garbage Collector.</returns>
|
||||
public ImpersonationHandle ImpersonateClient()
|
||||
{
|
||||
@@ -226,7 +227,7 @@ namespace NSspi.Contexts
|
||||
|
||||
this.ContextHandle.DangerousRelease();
|
||||
|
||||
this.impersonating = true;
|
||||
this.impersonating = status == SecurityStatus.OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +243,12 @@ namespace NSspi.Contexts
|
||||
{
|
||||
throw new SSPIException( "Failed to impersonate the client", status );
|
||||
}
|
||||
|
||||
|
||||
if( this.impersonating && this.impersonationSetsThreadPrinciple )
|
||||
{
|
||||
Thread.CurrentPrincipal = new WindowsPrincipal( (WindowsIdentity)GetRemoteIdentity() );
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -288,6 +294,10 @@ namespace NSspi.Contexts
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resources associted with the ServerContext.
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose( bool disposing )
|
||||
{
|
||||
// We were disposed while impersonating. This means that the consumer that is currently holding
|
||||
@@ -306,4 +316,4 @@ namespace NSspi.Contexts
|
||||
base.Dispose( disposing );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
NSspi/Credentials/AuthData.cs
Normal file
55
NSspi/Credentials/AuthData.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides authentication data in native method calls.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implements the 'SEC_WINNT_AUTH_IDENTITY' structure. See:
|
||||
///
|
||||
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380131(v=vs.85).aspx
|
||||
/// </remarks>
|
||||
[StructLayout( LayoutKind.Sequential )]
|
||||
internal struct NativeAuthData
|
||||
{
|
||||
public NativeAuthData( string domain, string username, string password, NativeAuthDataFlag flag )
|
||||
{
|
||||
this.Domain = domain;
|
||||
this.DomainLength = domain.Length;
|
||||
|
||||
this.User = username;
|
||||
this.UserLength = username.Length;
|
||||
|
||||
this.Password = password;
|
||||
this.PasswordLength = password.Length;
|
||||
|
||||
this.Flags = flag;
|
||||
}
|
||||
|
||||
[MarshalAs( UnmanagedType.LPWStr )]
|
||||
public string User;
|
||||
|
||||
public int UserLength;
|
||||
|
||||
[MarshalAs( UnmanagedType.LPWStr )]
|
||||
public string Domain;
|
||||
|
||||
public int DomainLength;
|
||||
|
||||
[MarshalAs( UnmanagedType.LPWStr )]
|
||||
public string Password;
|
||||
|
||||
public int PasswordLength;
|
||||
|
||||
public NativeAuthDataFlag Flags;
|
||||
}
|
||||
|
||||
internal enum NativeAuthDataFlag : int
|
||||
{
|
||||
Ansi = 1,
|
||||
|
||||
Unicode = 2
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the credentials of the user running the current process, for use as an SSPI client.
|
||||
/// </summary>
|
||||
public class ClientCredential : CurrentCredential
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ClientCredential class.
|
||||
/// </summary>
|
||||
/// <param name="package">The security package to acquire the credential handle from.</param>
|
||||
public ClientCredential( string package )
|
||||
: base( package, CredentialUse.Outbound )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
20
NSspi/Credentials/ClientCurrentCredential.cs
Normal file
20
NSspi/Credentials/ClientCurrentCredential.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a handle to the credentials of the user running the current process, to be used to
|
||||
/// authenticate as a client.
|
||||
/// </summary>
|
||||
public class ClientCurrentCredential : CurrentCredential
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ClientCurrentCredential class.
|
||||
/// </summary>
|
||||
/// <param name="package">The security package to acquire the credential handle from.</param>
|
||||
public ClientCurrentCredential( string package )
|
||||
: base( package, CredentialUse.Outbound )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSspi.Credentials;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
@@ -16,16 +9,16 @@ namespace NSspi.Credentials
|
||||
/// </summary>
|
||||
public class Credential : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the security package that controls the credential.
|
||||
/// </summary>
|
||||
private readonly string securityPackage;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the Credential has been disposed.
|
||||
/// </summary>
|
||||
private bool disposed;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the security package that controls the credential.
|
||||
/// </summary>
|
||||
private string securityPackage;
|
||||
|
||||
/// <summary>
|
||||
/// A safe handle to the credential's handle.
|
||||
/// </summary>
|
||||
@@ -42,14 +35,13 @@ namespace NSspi.Credentials
|
||||
/// <param name="package">The security package to acquire the credential from.</param>
|
||||
public Credential( string package )
|
||||
{
|
||||
this.disposed = false;
|
||||
this.securityPackage = package;
|
||||
|
||||
this.disposed = false;
|
||||
this.expiry = DateTime.MinValue;
|
||||
|
||||
this.PackageInfo = PackageSupport.GetPackageCapabilities( this.SecurityPackage );
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets metadata for the security package associated with the credential.
|
||||
/// </summary>
|
||||
@@ -151,7 +143,7 @@ namespace NSspi.Credentials
|
||||
protected set
|
||||
{
|
||||
CheckLifecycle();
|
||||
|
||||
|
||||
this.expiry = value;
|
||||
}
|
||||
}
|
||||
@@ -185,11 +177,15 @@ namespace NSspi.Credentials
|
||||
GC.SuppressFinalize( this );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resources associted with the credential.
|
||||
/// </summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected virtual void Dispose( bool disposing )
|
||||
{
|
||||
if ( this.disposed == false )
|
||||
if( this.disposed == false )
|
||||
{
|
||||
if ( disposing )
|
||||
if( disposing )
|
||||
{
|
||||
this.safeCredHandle.Dispose();
|
||||
}
|
||||
@@ -206,4 +202,4 @@ namespace NSspi.Credentials
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSspi.Credentials;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
internal static class CredentialNativeMethods
|
||||
{
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus AcquireCredentialsHandle(
|
||||
string principleName,
|
||||
@@ -25,13 +20,27 @@ namespace NSspi.Credentials
|
||||
ref TimeStamp expiry
|
||||
);
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus AcquireCredentialsHandle_AuthData(
|
||||
string principleName,
|
||||
string packageName,
|
||||
CredentialUse credentialUse,
|
||||
IntPtr loginId,
|
||||
ref NativeAuthData authData,
|
||||
IntPtr getKeyFunc,
|
||||
IntPtr getKeyData,
|
||||
ref RawSspiHandle credentialHandle,
|
||||
ref TimeStamp expiry
|
||||
);
|
||||
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus FreeCredentialsHandle(
|
||||
ref RawSspiHandle credentialHandle
|
||||
);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The overload of the QueryCredentialsAttribute method that is used for querying the name attribute.
|
||||
/// In this call, it takes a void* to a structure that contains a wide char pointer. The wide character
|
||||
@@ -49,4 +58,4 @@ namespace NSspi.Credentials
|
||||
ref QueryNameAttribCarrier name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
@@ -16,4 +12,4 @@ namespace NSspi.Credentials
|
||||
/// </summary>
|
||||
Names = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
@@ -29,4 +25,4 @@ namespace NSspi.Credentials
|
||||
/// </summary>
|
||||
Both = 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
@@ -38,7 +34,7 @@ namespace NSspi.Credentials
|
||||
this.Handle = new SafeCredentialHandle();
|
||||
|
||||
// The finally clause is the actual constrained region. The VM pre-allocates any stack space,
|
||||
// performs any allocations it needs to prepare methods for execution, and postpones any
|
||||
// performs any allocations it needs to prepare methods for execution, and postpones any
|
||||
// instances of the 'uncatchable' exceptions (ThreadAbort, StackOverflow, OutOfMemory).
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { }
|
||||
@@ -57,13 +53,12 @@ namespace NSspi.Credentials
|
||||
);
|
||||
}
|
||||
|
||||
if ( status != SecurityStatus.OK )
|
||||
if( status != SecurityStatus.OK )
|
||||
{
|
||||
throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
|
||||
}
|
||||
|
||||
this.Expiry = rawExpiry.ToDateTime();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
78
NSspi/Credentials/PasswordCredential.cs
Normal file
78
NSspi/Credentials/PasswordCredential.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents credentials acquired by providing a username, password, and domain.
|
||||
/// </summary>
|
||||
public class PasswordCredential : Credential
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PasswordCredential class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is possible to acquire a valid handle to credentials that do not provide a valid
|
||||
/// username-password combination. The username and password are not validation until the
|
||||
/// authentication cycle begins.
|
||||
/// </remarks>
|
||||
/// <param name="domain">The domain to authenticate to.</param>
|
||||
/// <param name="username">The username of the user to authenticate as.</param>
|
||||
/// <param name="password">The user's password.</param>
|
||||
/// <param name="secPackage">The SSPI security package to create credentials for.</param>
|
||||
/// <param name="use">
|
||||
/// Specify inbound when acquiring credentials for a server; outbound for a client.
|
||||
/// </param>
|
||||
public PasswordCredential( string domain, string username, string password, string secPackage, CredentialUse use )
|
||||
: base( secPackage )
|
||||
{
|
||||
NativeAuthData authData = new NativeAuthData( domain, username, password, NativeAuthDataFlag.Unicode );
|
||||
|
||||
Init( authData, secPackage, use );
|
||||
}
|
||||
|
||||
private void Init( NativeAuthData authData, string secPackage, CredentialUse use )
|
||||
{
|
||||
string packageName;
|
||||
TimeStamp rawExpiry = new TimeStamp();
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
|
||||
// -- Package --
|
||||
// Copy off for the call, since this.SecurityPackage is a property.
|
||||
packageName = this.SecurityPackage;
|
||||
|
||||
this.Handle = new SafeCredentialHandle();
|
||||
|
||||
|
||||
// The finally clause is the actual constrained region. The VM pre-allocates any stack space,
|
||||
// performs any allocations it needs to prepare methods for execution, and postpones any
|
||||
// instances of the 'uncatchable' exceptions (ThreadAbort, StackOverflow, OutOfMemory).
|
||||
RuntimeHelpers.PrepareConstrainedRegions();
|
||||
try { }
|
||||
finally
|
||||
{
|
||||
status = CredentialNativeMethods.AcquireCredentialsHandle_AuthData(
|
||||
null,
|
||||
packageName,
|
||||
use,
|
||||
IntPtr.Zero,
|
||||
ref authData,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
ref this.Handle.rawHandle,
|
||||
ref rawExpiry
|
||||
);
|
||||
}
|
||||
|
||||
if( status != SecurityStatus.OK )
|
||||
{
|
||||
throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
|
||||
}
|
||||
|
||||
this.Expiry = rawExpiry.ToDateTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
@@ -14,9 +10,9 @@ namespace NSspi.Credentials
|
||||
internal struct QueryNameAttribCarrier
|
||||
{
|
||||
/// <summary>
|
||||
/// A pointer to a null-terminated ascii-encoded containing the principle name
|
||||
/// A pointer to a null-terminated ascii-encoded containing the principle name
|
||||
/// associated with a credential
|
||||
/// </summary>
|
||||
public IntPtr Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
@@ -12,10 +8,17 @@ namespace NSspi.Credentials
|
||||
/// </summary>
|
||||
public class SafeCredentialHandle : SafeSspiHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeCredentialHandle"/> class.
|
||||
/// </summary>
|
||||
public SafeCredentialHandle()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Releases the resources held by the credential handle.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
@@ -28,5 +31,4 @@ namespace NSspi.Credentials
|
||||
return status == SecurityStatus.OK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Credentials
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the credentials of the user running the current process, for use as an SSPI server.
|
||||
/// Represents a handle to the credentials of the user running the current process, to be used to
|
||||
/// authenticate as a server.
|
||||
/// </summary>
|
||||
public class ServerCredential : CurrentCredential
|
||||
public class ServerCurrentCredential : CurrentCredential
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
||||
/// 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 ServerCurrentCredential( string package )
|
||||
: base( package, CredentialUse.Inbound )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Tags an enumeration member with a string that can be programmatically accessed.
|
||||
/// </summary>
|
||||
[AttributeUsage( AttributeTargets.Field )]
|
||||
public class EnumStringAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnumStringAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The string to associate with the enumeration member.</param>
|
||||
public EnumStringAttribute( string text )
|
||||
{
|
||||
this.Text = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string associated with the enumeration member.
|
||||
/// </summary>
|
||||
public string Text { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts betwen enumeration members and the strings associated to the members through the
|
||||
/// <see cref="EnumStringAttribute"/> type.
|
||||
/// </summary>
|
||||
public class EnumMgr
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text associated with the given enumeration member through a <see cref="EnumStringAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToText( Enum value )
|
||||
{
|
||||
FieldInfo field = value.GetType().GetField( value.ToString() );
|
||||
@@ -35,6 +51,12 @@ namespace NSspi
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the enumeration member that is tagged with the given text using the <see cref="EnumStringAttribute"/> type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The enumeration type to inspect.</typeparam>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static T FromText<T>( string text )
|
||||
{
|
||||
FieldInfo[] fields = typeof( T ).GetFields();
|
||||
@@ -57,4 +79,4 @@ namespace NSspi
|
||||
throw new ArgumentException( "Could not find a matching enumeration value for the text '" + text + "'." );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{4B4CD933-BF62-4F92-B8FA-6771758C5197}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
|
||||
<RootNamespace>NSspi</RootNamespace>
|
||||
<AssemblyName>NSspi</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\NSspi.XML</DocumentationFile>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>Kevin Thompson</Authors>
|
||||
<PackageReleaseNotes>Adds support for accessing the remote identity.</PackageReleaseNotes>
|
||||
<PackageProjectUrl>https://github.com/antiduh/nsspi</PackageProjectUrl>
|
||||
<Version>0.3.1.0</Version>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<AssemblyOriginatorKeyFile>nsspi key.snk</AssemblyOriginatorKeyFile>
|
||||
<PackageLicenseFile>License.txt</PackageLicenseFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Data" />
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<PackageReference Include="System.Security.Principal.Windows" Version="4.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="ByteWriter.cs" />
|
||||
<Compile Include="Contexts\ClientContext.cs" />
|
||||
<Compile Include="Contexts\Context.cs" />
|
||||
<Compile Include="Contexts\ContextAttrib.cs" />
|
||||
<Compile Include="Contexts\ContextNativeMethods.cs" />
|
||||
<Compile Include="Contexts\ContextQueries.cs" />
|
||||
<Compile Include="Contexts\ContextQueryAttrib.cs" />
|
||||
<Compile Include="Contexts\ImpersonationHandle.cs" />
|
||||
<Compile Include="Contexts\SafeContextHandle.cs" />
|
||||
<Compile Include="Credentials\CurrentCredential.cs" />
|
||||
<Compile Include="EnumMgr.cs" />
|
||||
<Compile Include="SecPkgInfo.cs" />
|
||||
<Compile Include="Contexts\ServerContext.cs" />
|
||||
<Compile Include="Credentials\ClientCredential.cs" />
|
||||
<Compile Include="Credentials\Credential.cs" />
|
||||
<Compile Include="Credentials\CredentialNativeMethods.cs" />
|
||||
<Compile Include="Credentials\CredentialQueryAttrib.cs" />
|
||||
<Compile Include="Credentials\CredentialUse.cs" />
|
||||
<Compile Include="Credentials\QueryNameSupport.cs" />
|
||||
<Compile Include="Credentials\SafeCredentialHandle.cs" />
|
||||
<Compile Include="Credentials\ServerCredential.cs" />
|
||||
<Compile Include="NativeMethods.cs" />
|
||||
<Compile Include="PackageSupport.cs" />
|
||||
<Compile Include="PackageNames.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SecureBuffer\SecureBuffer.cs" />
|
||||
<Compile Include="SecureBuffer\SecureBufferAdapter.cs" />
|
||||
<Compile Include="SecureBuffer\SecureBufferDataRep.cs" />
|
||||
<Compile Include="SecureBuffer\SecureBufferDesc.cs" />
|
||||
<Compile Include="SecureBuffer\SecureBufferType.cs" />
|
||||
<Compile Include="SecurityStatus.cs" />
|
||||
<Compile Include="SSPIException.cs" />
|
||||
<Compile Include="SspiHandle.cs" />
|
||||
<Compile Include="TimeStamp.cs" />
|
||||
<None Include="..\License.txt">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="NSspi.nuspec" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>NSspi</id>
|
||||
<version>0.1.3.0</version>
|
||||
<authors>Kevin Thompson</authors>
|
||||
<owners>Kevin Thompson</owners>
|
||||
<projectUrl>https://github.com/antiduh/nsspi</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>
|
||||
A C#/.Net interface to the Win32 SSPI authentication API,
|
||||
better known as Windows Integrated Authentication.
|
||||
</description>
|
||||
<language>C#</language>
|
||||
<releaseNotes>First release of NSspi.</releaseNotes>
|
||||
<copyright>Copyright 2017</copyright>
|
||||
</metadata>
|
||||
</package>
|
||||
@@ -1,21 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSspi.Contexts;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
||||
|
||||
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo );
|
||||
@@ -24,5 +18,8 @@ namespace NSspi
|
||||
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
|
||||
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
|
||||
|
||||
[DllImport( "Kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true )]
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
internal static extern bool CloseHandle( IntPtr handle );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
@@ -26,4 +22,4 @@ namespace NSspi
|
||||
/// </summary>
|
||||
public const string Ntlm = "NTLM";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
@@ -24,7 +20,7 @@ namespace NSspi
|
||||
SecurityStatus status = SecurityStatus.InternalError;
|
||||
|
||||
IntPtr rawInfoPtr;
|
||||
|
||||
|
||||
rawInfoPtr = new IntPtr();
|
||||
info = new SecPkgInfo();
|
||||
|
||||
@@ -35,11 +31,11 @@ namespace NSspi
|
||||
{
|
||||
status = NativeMethods.QuerySecurityPackageInfo( packageName, ref rawInfoPtr );
|
||||
|
||||
if ( rawInfoPtr != IntPtr.Zero )
|
||||
if( rawInfoPtr != IntPtr.Zero )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( status == SecurityStatus.OK )
|
||||
if( status == SecurityStatus.OK )
|
||||
{
|
||||
// This performs allocations as it makes room for the strings contained in the SecPkgInfo class.
|
||||
Marshal.PtrToStructure( rawInfoPtr, info );
|
||||
@@ -71,7 +67,7 @@ namespace NSspi
|
||||
IntPtr pkgArrayPtr;
|
||||
IntPtr pkgPtr;
|
||||
int numPackages = 0;
|
||||
int pkgSize = Marshal.SizeOf( typeof(SecPkgInfo) );
|
||||
int pkgSize = Marshal.SizeOf( typeof( SecPkgInfo ) );
|
||||
|
||||
pkgArrayPtr = new IntPtr();
|
||||
|
||||
@@ -90,7 +86,7 @@ namespace NSspi
|
||||
// Bwooop Bwooop Alocation Alert
|
||||
// 1) We allocate the array
|
||||
// 2) We allocate the individual elements in the array (they're class objects).
|
||||
// 3) We allocate the strings in the individual elements in the array when we
|
||||
// 3) We allocate the strings in the individual elements in the array when we
|
||||
// call Marshal.PtrToStructure()
|
||||
|
||||
packages = new SecPkgInfo[numPackages];
|
||||
@@ -99,7 +95,7 @@ namespace NSspi
|
||||
{
|
||||
packages[i] = new SecPkgInfo();
|
||||
}
|
||||
|
||||
|
||||
for( int i = 0; i < numPackages; i++ )
|
||||
{
|
||||
pkgPtr = IntPtr.Add( pkgArrayPtr, i * pkgSize );
|
||||
@@ -123,4 +119,4 @@ namespace NSspi
|
||||
return packages;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,9 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("NSspi")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Kevin Thompson")]
|
||||
[assembly: AssemblyProduct("NSspi")]
|
||||
[assembly: AssemblyCopyright("Copyright © Kevin Thompson 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: ComVisible( false )]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("9abf710c-c646-42aa-8183-76bfa141a07b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.1.3.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.2.0")]
|
||||
[assembly: Guid( "9abf710c-c646-42aa-8183-76bfa141a07b" )]
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
@@ -26,7 +22,7 @@ namespace NSspi
|
||||
this.message = message;
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the SSPIException class from serialization data.
|
||||
/// </summary>
|
||||
@@ -35,7 +31,7 @@ namespace NSspi
|
||||
protected SSPIException( SerializationInfo info, StreamingContext context )
|
||||
: base( info, context )
|
||||
{
|
||||
this.message = info.GetString("message");
|
||||
this.message = info.GetString( "message" );
|
||||
this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" );
|
||||
}
|
||||
|
||||
@@ -70,13 +66,13 @@ namespace NSspi
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format(
|
||||
"{0}. Error Code = '0x{1:X}' - \"{2}\".",
|
||||
this.message,
|
||||
this.errorCode,
|
||||
EnumMgr.ToText(this.errorCode)
|
||||
return string.Format(
|
||||
"{0}. Error Code = '0x{1:X}' - \"{2}\".",
|
||||
this.message,
|
||||
this.errorCode,
|
||||
EnumMgr.ToText( this.errorCode )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
@@ -47,55 +43,55 @@ namespace NSspi
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the capabilities of a security package.
|
||||
/// Describes the capabilities of a security package.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum SecPkgCapability : uint
|
||||
public enum SecPkgCapability : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the package supports generating messages with integrity information. Required for MakeSignature and VerifySignature.
|
||||
/// </summary>
|
||||
Integrity = 0x1,
|
||||
Integrity = 0x1,
|
||||
|
||||
/// <summary>
|
||||
/// Whether the package supports generating encrypted messages. Required for EncryptMessage and DecryptMessage.
|
||||
/// </summary>
|
||||
Privacy = 0x2,
|
||||
Privacy = 0x2,
|
||||
|
||||
/// <summary>
|
||||
/// Whether the package uses any other buffer information than token buffers.
|
||||
/// </summary>
|
||||
TokenOnly = 0x4,
|
||||
TokenOnly = 0x4,
|
||||
|
||||
/// <summary>
|
||||
/// Whether the package supports datagram-style authentication.
|
||||
/// </summary>
|
||||
Datagram = 0x8,
|
||||
Datagram = 0x8,
|
||||
|
||||
/// <summary>
|
||||
/// Whether the package supports creating contexts with connection semantics
|
||||
/// </summary>
|
||||
Connection = 0x10,
|
||||
Connection = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// Multiple legs are neccessary for authentication.
|
||||
/// </summary>
|
||||
MultiLeg = 0x20,
|
||||
MultiLeg = 0x20,
|
||||
|
||||
/// <summary>
|
||||
/// Server authentication is not supported.
|
||||
/// </summary>
|
||||
ClientOnly = 0x40,
|
||||
ClientOnly = 0x40,
|
||||
|
||||
/// <summary>
|
||||
/// Supports extended error handling facilities.
|
||||
/// </summary>
|
||||
ExtendedError = 0x80,
|
||||
ExtendedError = 0x80,
|
||||
|
||||
/// <summary>
|
||||
/// Supports client impersonation on the server.
|
||||
/// </summary>
|
||||
Impersonation = 0x100,
|
||||
Impersonation = 0x100,
|
||||
|
||||
/// <summary>
|
||||
/// Understands Windows princple and target names.
|
||||
@@ -105,45 +101,45 @@ namespace NSspi
|
||||
/// <summary>
|
||||
/// Supports stream semantics
|
||||
/// </summary>
|
||||
Stream = 0x400,
|
||||
Stream = 0x400,
|
||||
|
||||
/// <summary>
|
||||
/// Package may be used by the Negiotiate meta-package.
|
||||
/// </summary>
|
||||
Negotiable = 0x800,
|
||||
Negotiable = 0x800,
|
||||
|
||||
/// <summary>
|
||||
/// Compatible with GSS.
|
||||
/// </summary>
|
||||
GssCompatible = 0x1000,
|
||||
GssCompatible = 0x1000,
|
||||
|
||||
/// <summary>
|
||||
/// Supports LsaLogonUser
|
||||
/// </summary>
|
||||
Logon = 0x2000,
|
||||
Logon = 0x2000,
|
||||
|
||||
/// <summary>
|
||||
/// Token buffers are in Ascii format.
|
||||
/// </summary>
|
||||
AsciiBuffers = 0x4000,
|
||||
AsciiBuffers = 0x4000,
|
||||
|
||||
/// <summary>
|
||||
/// Supports separating large tokens into multiple buffers.
|
||||
/// </summary>
|
||||
Fragment = 0x8000,
|
||||
Fragment = 0x8000,
|
||||
|
||||
/// <summary>
|
||||
/// Supports mutual authentication between a client and server.
|
||||
/// </summary>
|
||||
MutualAuth = 0x10000,
|
||||
MutualAuth = 0x10000,
|
||||
|
||||
/// <summary>
|
||||
/// Supports credential delegation from the server to a third context.
|
||||
/// </summary>
|
||||
Delegation = 0x20000,
|
||||
Delegation = 0x20000,
|
||||
|
||||
/// <summary>
|
||||
/// Supports calling EncryptMessage with the read-only-checksum flag, which protects data only
|
||||
/// Supports calling EncryptMessage with the read-only-checksum flag, which protects data only
|
||||
/// with a checksum and does not encrypt it.
|
||||
/// </summary>
|
||||
ReadOnlyChecksum = 0x40000,
|
||||
@@ -157,11 +153,11 @@ namespace NSspi
|
||||
/// <summary>
|
||||
/// Extends the negotiate package; only one such package may be registered at any time.
|
||||
/// </summary>
|
||||
ExtendsNego = 0x00100000,
|
||||
ExtendsNego = 0x00100000,
|
||||
|
||||
/// <summary>
|
||||
/// This package is negotiated by the package of type ExtendsNego.
|
||||
/// </summary>
|
||||
Negotiable2 = 0x00200000,
|
||||
Negotiable2 = 0x00200000,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
@@ -37,10 +33,10 @@ namespace NSspi.Buffers
|
||||
/// </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
|
||||
/// 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>
|
||||
@@ -50,7 +46,7 @@ namespace NSspi.Buffers
|
||||
/// 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
|
||||
/// <param name="type">The type or purpose of the buffer, for purposes of
|
||||
/// invoking the native API.</param>
|
||||
public SecureBuffer( byte[] buffer, BufferType type )
|
||||
{
|
||||
@@ -75,4 +71,4 @@ namespace NSspi.Buffers
|
||||
/// </summary>
|
||||
public int Length { get; internal set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
@@ -13,52 +10,52 @@ namespace NSspi.Buffers
|
||||
/// </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
|
||||
///
|
||||
/// 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
|
||||
/// * 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.
|
||||
///
|
||||
/// 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
|
||||
/// |-- 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.
|
||||
///
|
||||
/// 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
|
||||
@@ -120,7 +117,7 @@ namespace NSspi.Buffers
|
||||
this.bufferHandles = new GCHandle[this.buffers.Count];
|
||||
this.bufferCarrier = new SecureBufferInternal[this.buffers.Count];
|
||||
|
||||
for ( int i = 0; i < this.buffers.Count; i++ )
|
||||
for( int i = 0; i < this.buffers.Count; i++ )
|
||||
{
|
||||
this.bufferHandles[i] = GCHandle.Alloc( this.buffers[i].Buffer, GCHandleType.Pinned );
|
||||
|
||||
@@ -156,7 +153,7 @@ namespace NSspi.Buffers
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( this.disposed )
|
||||
if( this.disposed )
|
||||
{
|
||||
throw new ObjectDisposedException( "Cannot use SecureBufferListHandle after it has been disposed" );
|
||||
}
|
||||
@@ -184,11 +181,11 @@ namespace NSspi.Buffers
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
private void Dispose( bool disposing )
|
||||
{
|
||||
if ( this.disposed == true ) { return; }
|
||||
if( this.disposed == true ) { return; }
|
||||
|
||||
if ( disposing )
|
||||
if( disposing )
|
||||
{
|
||||
// When this class is actually being used for its original purpose - to convey buffers
|
||||
// When this class is actually being used for its original purpose - to convey buffers
|
||||
// back and forth to SSPI calls - we need to copy the potentially modified structure members
|
||||
// back to our caller's buffer.
|
||||
for( int i = 0; i < this.buffers.Count; i++ )
|
||||
@@ -218,4 +215,4 @@ namespace NSspi.Buffers
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
@@ -22,4 +18,4 @@ namespace NSspi.Buffers
|
||||
/// </summary>
|
||||
Network = 0x00
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
@@ -12,7 +7,7 @@ namespace NSspi.Buffers
|
||||
/// 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
|
||||
{
|
||||
/// <summary>
|
||||
@@ -35,4 +30,4 @@ namespace NSspi.Buffers
|
||||
/// </summary>
|
||||
public const int ApiVersion = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi.Buffers
|
||||
{
|
||||
@@ -38,7 +34,7 @@ namespace NSspi.Buffers
|
||||
|
||||
/// <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
|
||||
/// 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,
|
||||
@@ -57,7 +53,7 @@ namespace NSspi.Buffers
|
||||
Stream = 0x0A,
|
||||
ChannelBindings = 0x0E,
|
||||
TargetHost = 0x10,
|
||||
ReadOnlyFlag = unchecked( (int)0x80000000 ),
|
||||
ReadOnlyFlag = unchecked((int)0x80000000),
|
||||
ReadOnlyWithChecksum = 0x10000000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/*
|
||||
// From winerror.h
|
||||
// From winerror.h
|
||||
#define SEC_E_OK ((HRESULT)0x00000000L)
|
||||
#define SEC_E_INSUFFICIENT_MEMORY _HRESULT_TYPEDEF_(0x80090300L)
|
||||
#define SEC_E_INVALID_HANDLE _HRESULT_TYPEDEF_(0x80090301L)
|
||||
@@ -31,8 +27,8 @@ namespace NSspi
|
||||
/// The request completed successfully
|
||||
/// </summary>
|
||||
[EnumString( "No error" )]
|
||||
OK = 0x00000000,
|
||||
|
||||
OK = 0x00000000,
|
||||
|
||||
/// <summary>
|
||||
/// The token returned by the context needs to be provided to the cooperating party
|
||||
/// to continue construction of the context.
|
||||
@@ -45,7 +41,7 @@ namespace NSspi
|
||||
/// must call CompleteAuthToken.
|
||||
/// </summary>
|
||||
[EnumString( "Authentication cycle needs to perform a 'complete'." )]
|
||||
CompleteNeeded = 0x00090313,
|
||||
CompleteNeeded = 0x00090313,
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after a client calls InitializeSecurityContext to indicate that the client
|
||||
@@ -60,70 +56,128 @@ namespace NSspi
|
||||
[EnumString( "The security context was used after its expiration time passed." )]
|
||||
ContextExpired = 0x00090317,
|
||||
|
||||
/// <summary>
|
||||
/// The credentials supplied to the security context were not fully initialized.
|
||||
/// </summary>
|
||||
[EnumString( "The credentials supplied to the security context were not fully initialized." )]
|
||||
CredentialsNeeded = 0x00090320,
|
||||
|
||||
[EnumString( "The context data must be re-negotiated with the peer" )]
|
||||
Renegotiate = 0x00090321,
|
||||
/// <summary>
|
||||
/// The context data must be re-negotiated with the peer.
|
||||
/// </summary>
|
||||
[EnumString( "The context data must be re-negotiated with the peer." )]
|
||||
Renegotiate = 0x00090321,
|
||||
|
||||
// Errors
|
||||
[EnumString( "Not enough memory.")]
|
||||
OutOfMemory = 0x80090300,
|
||||
// -------------- Errors --------------
|
||||
|
||||
[EnumString( "The handle provided to the API was invalid.")]
|
||||
InvalidHandle = 0x80090301,
|
||||
/// <summary>
|
||||
/// The SSPI operation failed due to insufficient memory resources.
|
||||
/// </summary>
|
||||
[EnumString( "Not enough memory." )]
|
||||
OutOfMemory = 0x80090300,
|
||||
|
||||
[EnumString( "The attempted operation is not supported")]
|
||||
Unsupported = 0x80090302,
|
||||
/// <summary>
|
||||
/// The handle provided to the API was invalid.
|
||||
/// </summary>
|
||||
[EnumString( "The handle provided to the API was invalid." )]
|
||||
InvalidHandle = 0x80090301,
|
||||
|
||||
[EnumString( "The specified principle is not known in the authentication system.")]
|
||||
TargetUnknown = 0x80090303,
|
||||
|
||||
[EnumString( "An internal error occurred" )]
|
||||
InternalError = 0x80090304,
|
||||
/// <summary>
|
||||
/// The attempted operation is not supported.
|
||||
/// </summary>
|
||||
[EnumString( "The attempted operation is not supported." )]
|
||||
Unsupported = 0x80090302,
|
||||
|
||||
/// <summary>
|
||||
/// The specified principle is not known in the authentication system.
|
||||
/// </summary>
|
||||
[EnumString( "The specified principle is not known in the authentication system." )]
|
||||
TargetUnknown = 0x80090303,
|
||||
|
||||
/// <summary>
|
||||
/// An internal error occurred
|
||||
/// </summary>
|
||||
[EnumString( "An internal error occurred." )]
|
||||
InternalError = 0x80090304,
|
||||
|
||||
/// <summary>
|
||||
/// No security provider package was found with the given name.
|
||||
/// </summary>
|
||||
[EnumString( "The requested security package was not found.")]
|
||||
PackageNotFound = 0x80090305,
|
||||
[EnumString( "The requested security package was not found." )]
|
||||
PackageNotFound = 0x80090305,
|
||||
|
||||
NotOwner = 0x80090306,
|
||||
CannotInstall = 0x80090307,
|
||||
/// <summary>
|
||||
/// Cannot use the provided credentials, the caller is not the owner of the credentials.
|
||||
/// </summary>
|
||||
[EnumString( "The caller is not the owner of the desired credentials." )]
|
||||
NotOwner = 0x80090306,
|
||||
|
||||
/// <summary>
|
||||
/// The requested security package failed to initalize, and thus cannot be used.
|
||||
/// </summary>
|
||||
[EnumString( "The requested security package failed to initalize, and thus cannot be used." )]
|
||||
CannotInstall = 0x80090307,
|
||||
|
||||
/// <summary>
|
||||
/// A token was provided that contained incorrect or corrupted data.
|
||||
/// </summary>
|
||||
[EnumString("The provided authentication token is invalid or corrupted.")]
|
||||
InvalidToken = 0x80090308,
|
||||
|
||||
CannotPack = 0x80090309,
|
||||
QopNotSupported = 0x8009030A,
|
||||
[EnumString( "The provided authentication token is invalid or corrupted." )]
|
||||
InvalidToken = 0x80090308,
|
||||
|
||||
/// <summary>
|
||||
/// The security package is not able to marshall the logon buffer, so the logon attempt has failed
|
||||
/// </summary>
|
||||
[EnumString( "The security package is not able to marshall the logon buffer, so the logon attempt has failed." )]
|
||||
CannotPack = 0x80090309,
|
||||
|
||||
/// <summary>
|
||||
/// The per-message Quality of Protection is not supported by the security package.
|
||||
/// </summary>
|
||||
[EnumString( "The per-message Quality of Protection is not supported by the security package." )]
|
||||
QopNotSupported = 0x8009030A,
|
||||
|
||||
/// <summary>
|
||||
/// Impersonation is not supported.
|
||||
/// </summary>
|
||||
[EnumString("Impersonation is not supported with the current security package.")]
|
||||
NoImpersonation = 0x8009030B,
|
||||
[EnumString( "Impersonation is not supported with the current security package." )]
|
||||
NoImpersonation = 0x8009030B,
|
||||
|
||||
[EnumString("The logon was denied, perhaps because the provided credentials were incorrect.")]
|
||||
LogonDenied = 0x8009030C,
|
||||
/// <summary>
|
||||
/// The logon was denied, perhaps because the provided credentials were incorrect.
|
||||
/// </summary>
|
||||
[EnumString( "The logon was denied, perhaps because the provided credentials were incorrect." )]
|
||||
LogonDenied = 0x8009030C,
|
||||
|
||||
/// <summary>
|
||||
/// The credentials provided are not recognized by the selected security package.
|
||||
/// </summary>
|
||||
[EnumString( "The credentials provided are not recognized by the selected security package." )]
|
||||
UnknownCredentials = 0x8009030D,
|
||||
|
||||
[EnumString( "The credentials provided are not recognized by the selected security package.")]
|
||||
UnknownCredentials = 0x8009030D,
|
||||
|
||||
[EnumString( "No credentials are available in the selected security package.")]
|
||||
NoCredentials = 0x8009030E,
|
||||
/// <summary>
|
||||
/// No credentials are available in the selected security package.
|
||||
/// </summary>
|
||||
[EnumString( "No credentials are available in the selected security package." )]
|
||||
NoCredentials = 0x8009030E,
|
||||
|
||||
/// <summary>
|
||||
/// A message that was provided to the Decrypt or VerifySignature functions was altered after
|
||||
/// it was created.
|
||||
/// </summary>
|
||||
[EnumString( "A message that was provided to the Decrypt or VerifySignature functions was altered " +
|
||||
"after it was created.")]
|
||||
MessageAltered = 0x8009030F,
|
||||
"after it was created." )]
|
||||
MessageAltered = 0x8009030F,
|
||||
|
||||
[EnumString( "A message was received out of the expected order.")]
|
||||
OutOfSequence = 0x80090310,
|
||||
/// <summary>
|
||||
/// A message was received out of the expected order.
|
||||
/// </summary>
|
||||
[EnumString( "A message was received out of the expected order." )]
|
||||
OutOfSequence = 0x80090310,
|
||||
|
||||
[EnumString( "The current security package cannot contact an authenticating authority.")]
|
||||
/// <summary>
|
||||
/// The current security package cannot contact an authenticating authority.
|
||||
/// </summary>
|
||||
[EnumString( "The current security package cannot contact an authenticating authority." )]
|
||||
NoAuthenticatingAuthority = 0x80090311,
|
||||
|
||||
/// <summary>
|
||||
@@ -132,25 +186,93 @@ namespace NSspi
|
||||
/// <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.
|
||||
/// 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,
|
||||
[EnumString( "The buffer provided to an SSPI API call contained a message that was not complete." )]
|
||||
IncompleteMessage = 0x80090318,
|
||||
|
||||
/// <summary>
|
||||
/// The credentials supplied were not complete, and could not be verified. The context could not be initialized.
|
||||
/// </summary>
|
||||
[EnumString( "The credentials supplied were not complete, and could not be verified. The context could not be initialized." )]
|
||||
IncompleteCredentials = 0x80090320,
|
||||
BufferNotEnough = 0x80090321,
|
||||
WrongPrincipal = 0x80090322,
|
||||
TimeSkew = 0x80090324,
|
||||
UntrustedRoot = 0x80090325,
|
||||
IllegalMessage = 0x80090326,
|
||||
CertUnknown = 0x80090327,
|
||||
CertExpired = 0x80090328,
|
||||
AlgorithmMismatch = 0x80090331,
|
||||
SecurityQosFailed = 0x80090332,
|
||||
|
||||
/// <summary>
|
||||
/// The buffers supplied to a security function were too small.
|
||||
/// </summary>
|
||||
[EnumString( "The buffers supplied to a security function were too small." )]
|
||||
BufferNotEnough = 0x80090321,
|
||||
|
||||
/// <summary>
|
||||
/// The target principal name is incorrect.
|
||||
/// </summary>
|
||||
[EnumString( "The target principal name is incorrect." )]
|
||||
WrongPrincipal = 0x80090322,
|
||||
|
||||
/// <summary>
|
||||
/// The clocks on the client and server machines are skewed.
|
||||
/// </summary>
|
||||
[EnumString( "The clocks on the client and server machines are skewed." )]
|
||||
TimeSkew = 0x80090324,
|
||||
|
||||
/// <summary>
|
||||
/// The certificate chain was issued by an authority that is not trusted.
|
||||
/// </summary>
|
||||
[EnumString( "The certificate chain was issued by an authority that is not trusted." )]
|
||||
UntrustedRoot = 0x80090325,
|
||||
|
||||
/// <summary>
|
||||
/// The message received was unexpected or badly formatted.
|
||||
/// </summary>
|
||||
[EnumString( "The message received was unexpected or badly formatted." )]
|
||||
IllegalMessage = 0x80090326,
|
||||
|
||||
/// <summary>
|
||||
/// An unknown error occurred while processing the certificate.
|
||||
/// </summary>
|
||||
[EnumString( "An unknown error occurred while processing the certificate." )]
|
||||
CertUnknown = 0x80090327,
|
||||
|
||||
/// <summary>
|
||||
/// The received certificate has expired.
|
||||
/// </summary>
|
||||
[EnumString( "The received certificate has expired." )]
|
||||
CertExpired = 0x80090328,
|
||||
|
||||
/// <summary>
|
||||
/// The client and server cannot communicate, because they do not possess a common algorithm.
|
||||
/// </summary>
|
||||
[EnumString( "The client and server cannot communicate, because they do not possess a common algorithm." )]
|
||||
AlgorithmMismatch = 0x80090331,
|
||||
|
||||
/// <summary>
|
||||
/// The security context could not be established due to a failure in the requested quality
|
||||
/// of service (e.g. mutual authentication or delegation).
|
||||
/// </summary>
|
||||
[EnumString( "The security context could not be established due to a failure in the requested " +
|
||||
"quality of service (e.g. mutual authentication or delegation)." )]
|
||||
SecurityQosFailed = 0x80090332,
|
||||
|
||||
/// <summary>
|
||||
/// Smartcard logon is required and was not used.
|
||||
/// </summary>
|
||||
[EnumString( "Smartcard logon is required and was not used." )]
|
||||
SmartcardLogonRequired = 0x8009033E,
|
||||
UnsupportedPreauth = 0x80090343,
|
||||
BadBinding = 0x80090346
|
||||
|
||||
/// <summary>
|
||||
/// An unsupported preauthentication mechanism was presented to the Kerberos package.
|
||||
/// </summary>
|
||||
[EnumString( "An unsupported preauthentication mechanism was presented to the Kerberos package." )]
|
||||
UnsupportedPreauth = 0x80090343,
|
||||
|
||||
/// <summary>
|
||||
/// Client's supplied SSPI channel bindings were incorrect.
|
||||
/// </summary>
|
||||
[EnumString( "Client's supplied SSPI channel bindings were incorrect." )]
|
||||
BadBinding = 0x80090346
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -168,5 +290,4 @@ namespace NSspi
|
||||
return (uint)status > 0x80000000u;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSspi.Contexts;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the raw structure for any handle created for the SSPI API, for example, credential
|
||||
/// handles, context handles, and security package handles. Any SSPI handle is always the size
|
||||
/// of two native pointers.
|
||||
/// Represents the raw structure for any handle created for the SSPI API, for example, credential
|
||||
/// handles, context handles, and security package handles. Any SSPI handle is always the size
|
||||
/// of two native pointers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The documentation for SSPI handles can be found here:
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa380495(v=vs.85).aspx
|
||||
///
|
||||
///
|
||||
/// 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.
|
||||
/// 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 performed a CER
|
||||
/// that employs handle reference counting across the native API invocation.
|
||||
/// </remarks>
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ]
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||
internal struct RawSspiHandle
|
||||
{
|
||||
private IntPtr lowPart;
|
||||
@@ -46,7 +40,7 @@ namespace NSspi
|
||||
/// <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()
|
||||
{
|
||||
this.lowPart = IntPtr.Zero;
|
||||
@@ -61,17 +55,27 @@ namespace NSspi
|
||||
{
|
||||
internal RawSspiHandle rawHandle;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SafeSspiHandle"/> class.
|
||||
/// </summary>
|
||||
protected SafeSspiHandle()
|
||||
: base( IntPtr.Zero, true )
|
||||
{
|
||||
this.rawHandle = new RawSspiHandle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the handle is invalid.
|
||||
/// </summary>
|
||||
public override bool IsInvalid
|
||||
{
|
||||
get { return IsClosed || this.rawHandle.IsZero(); }
|
||||
get { return IsClosed || this.rawHandle.IsZero(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks the handle as no longer being in use.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
@@ -79,4 +83,4 @@ namespace NSspi
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NSspi
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Windows API Timestamp structure, which stores time in units of 100 nanosecond
|
||||
/// 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 )]
|
||||
public struct TimeStamp
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the calendar date and time corresponding a zero timestamp.
|
||||
/// </summary>
|
||||
public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
||||
|
||||
/// <summary>
|
||||
@@ -29,13 +28,13 @@ namespace NSspi
|
||||
/// <returns></returns>
|
||||
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.
|
||||
// It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone
|
||||
// http://stackoverflow.com/questions/24478056/
|
||||
if ( test > (ulong)DateTime.MaxValue.Ticks )
|
||||
if( test > (ulong)DateTime.MaxValue.Ticks )
|
||||
{
|
||||
return DateTime.MaxValue;
|
||||
}
|
||||
@@ -45,4 +44,4 @@ namespace NSspi
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
NSspi/nsspi key.snk
Normal file
BIN
NSspi/nsspi key.snk
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
||||
</startup>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>NsspiDemo</RootNamespace>
|
||||
<AssemblyName>NsspiDemo</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
@@ -22,6 +22,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -31,6 +32,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -16,10 +16,10 @@ namespace NSspi
|
||||
|
||||
private static void CredTest( string packageName )
|
||||
{
|
||||
ClientCredential clientCred = null;
|
||||
ClientCurrentCredential clientCred = null;
|
||||
ClientContext client = null;
|
||||
|
||||
ServerCredential serverCred = null;
|
||||
ServerCurrentCredential serverCred = null;
|
||||
ServerContext server = null;
|
||||
|
||||
byte[] clientToken;
|
||||
@@ -30,24 +30,23 @@ namespace NSspi
|
||||
|
||||
try
|
||||
{
|
||||
clientCred = new ClientCredential( packageName );
|
||||
serverCred = new ServerCredential( packageName );
|
||||
clientCred = new ClientCurrentCredential( packageName );
|
||||
serverCred = new ServerCurrentCredential( packageName );
|
||||
|
||||
Console.Out.WriteLine( clientCred.PrincipleName );
|
||||
|
||||
client = new ClientContext(
|
||||
clientCred,
|
||||
serverCred.PrincipleName,
|
||||
ContextAttrib.MutualAuth |
|
||||
client = new ClientContext(
|
||||
clientCred,
|
||||
serverCred.PrincipleName,
|
||||
ContextAttrib.MutualAuth |
|
||||
ContextAttrib.InitIdentify |
|
||||
ContextAttrib.Confidentiality |
|
||||
ContextAttrib.ReplayDetect |
|
||||
ContextAttrib.SequenceDetect |
|
||||
ContextAttrib.SequenceDetect |
|
||||
ContextAttrib.Connection |
|
||||
ContextAttrib.Delegate
|
||||
);
|
||||
|
||||
|
||||
server = new ServerContext(
|
||||
serverCred,
|
||||
ContextAttrib.MutualAuth |
|
||||
@@ -64,18 +63,17 @@ namespace NSspi
|
||||
|
||||
clientStatus = client.Init( serverToken, out clientToken );
|
||||
|
||||
while ( true )
|
||||
while( true )
|
||||
{
|
||||
serverStatus = server.AcceptToken( clientToken, out serverToken );
|
||||
|
||||
if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||
if( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||
|
||||
clientStatus = client.Init( serverToken, out clientToken );
|
||||
|
||||
if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||
if( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||
}
|
||||
|
||||
|
||||
Console.Out.WriteLine( "Server authority: " + server.AuthorityName );
|
||||
Console.Out.WriteLine( "Server context user: " + server.ContextUserName );
|
||||
|
||||
@@ -102,7 +100,7 @@ namespace NSspi
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
for( int i= 0; i < plainText.Length; i++ )
|
||||
for( int i = 0; i < plainText.Length; i++ )
|
||||
{
|
||||
if( plainText[i] != roundTripPlaintext[i] )
|
||||
{
|
||||
@@ -117,25 +115,23 @@ namespace NSspi
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
|
||||
using( server.ImpersonateClient() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
cipherText = client.MakeSignature( plainText );
|
||||
|
||||
bool goodSig = server.VerifySignature( cipherText, out roundTripPlaintext );
|
||||
|
||||
if ( goodSig == false ||
|
||||
if( goodSig == false ||
|
||||
roundTripPlaintext.Length != plainText.Length )
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
for ( int i = 0; i < plainText.Length; i++ )
|
||||
|
||||
for( int i = 0; i < plainText.Length; i++ )
|
||||
{
|
||||
if ( plainText[i] != roundTripPlaintext[i] )
|
||||
if( plainText[i] != roundTripPlaintext[i] )
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
@@ -145,12 +141,12 @@ namespace NSspi
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ( server != null )
|
||||
if( server != null )
|
||||
{
|
||||
server.Dispose();
|
||||
}
|
||||
|
||||
if ( client != null )
|
||||
if( client != null )
|
||||
{
|
||||
client.Dispose();
|
||||
}
|
||||
@@ -160,11 +156,11 @@ namespace NSspi
|
||||
clientCred.Dispose();
|
||||
}
|
||||
|
||||
if ( serverCred != null )
|
||||
if( serverCred != null )
|
||||
{
|
||||
serverCred.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle( "NsspiDemo" )]
|
||||
@@ -14,8 +13,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTrademark( "" )]
|
||||
[assembly: AssemblyCulture( "" )]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible( false )]
|
||||
|
||||
@@ -25,12 +24,12 @@ using System.Runtime.InteropServices;
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion( "1.0.0.0" )]
|
||||
[assembly: AssemblyFileVersion( "1.0.0.0" )]
|
||||
[assembly: AssemblyFileVersion( "1.0.0.0" )]
|
||||
4
NsspiDemo/Properties/Resources.Designer.cs
generated
4
NsspiDemo/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -19,7 +19,7 @@ namespace NsspiDemo.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
4
NsspiDemo/Properties/Settings.Designer.cs
generated
4
NsspiDemo/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -12,7 +12,7 @@ namespace NsspiDemo.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
||||
</startup>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using NSspi;
|
||||
using NSspi.Contexts;
|
||||
@@ -20,7 +14,7 @@ namespace TestClient
|
||||
public partial class ClientForm : Form
|
||||
{
|
||||
private ClientContext context;
|
||||
private ClientCredential cred;
|
||||
private ClientCurrentCredential cred;
|
||||
|
||||
private CustomConnection connection;
|
||||
|
||||
@@ -48,16 +42,16 @@ namespace TestClient
|
||||
this.FormClosing += Form1_FormClosing;
|
||||
|
||||
// --- SSPI ---
|
||||
this.cred = new ClientCredential( PackageNames.Negotiate );
|
||||
this.cred = new ClientCurrentCredential( PackageNames.Negotiate );
|
||||
|
||||
this.context = new ClientContext(
|
||||
cred,
|
||||
"",
|
||||
ContextAttrib.InitIntegrity |
|
||||
ContextAttrib.ReplayDetect |
|
||||
ContextAttrib.SequenceDetect |
|
||||
ContextAttrib.MutualAuth |
|
||||
ContextAttrib.Delegate |
|
||||
ContextAttrib.InitIntegrity |
|
||||
ContextAttrib.ReplayDetect |
|
||||
ContextAttrib.SequenceDetect |
|
||||
ContextAttrib.MutualAuth |
|
||||
ContextAttrib.Delegate |
|
||||
ContextAttrib.Confidentiality
|
||||
);
|
||||
|
||||
@@ -107,7 +101,6 @@ namespace TestClient
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +109,6 @@ namespace TestClient
|
||||
this.connection.Stop();
|
||||
}
|
||||
|
||||
|
||||
private void encryptButton_Click( object sender, EventArgs e )
|
||||
{
|
||||
byte[] plaintext;
|
||||
@@ -149,7 +141,7 @@ namespace TestClient
|
||||
|
||||
private void connection_Received( Message message )
|
||||
{
|
||||
this.Invoke( (Action)delegate()
|
||||
this.Invoke( (Action)delegate ()
|
||||
{
|
||||
if( message.Operation == ProtocolOp.ServerToken )
|
||||
{
|
||||
@@ -180,11 +172,11 @@ namespace TestClient
|
||||
this.initializing = false;
|
||||
this.lastServerToken = null;
|
||||
|
||||
this.BeginInvoke( (Action)delegate()
|
||||
this.BeginInvoke( (Action)delegate ()
|
||||
{
|
||||
this.context.Dispose();
|
||||
this.context = new ClientContext(
|
||||
this.cred,
|
||||
this.context = new ClientContext(
|
||||
this.cred,
|
||||
"",
|
||||
ContextAttrib.InitIntegrity |
|
||||
ContextAttrib.ReplayDetect |
|
||||
@@ -195,9 +187,9 @@ namespace TestClient
|
||||
);
|
||||
|
||||
UpdateButtons();
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
private void DoInit()
|
||||
{
|
||||
SecurityStatus status;
|
||||
@@ -253,4 +245,4 @@ namespace TestClient
|
||||
this.signButton.Enabled = this.connected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TestClient
|
||||
{
|
||||
static class Program
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
private static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault( false );
|
||||
Application.Run( new ClientForm() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle( "TestClient" )]
|
||||
@@ -14,8 +13,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTrademark( "" )]
|
||||
[assembly: AssemblyCulture( "" )]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible( false )]
|
||||
|
||||
@@ -25,11 +24,11 @@ using System.Runtime.InteropServices;
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion( "1.0.0.0" )]
|
||||
|
||||
4
TestClient/Properties/Resources.Designer.cs
generated
4
TestClient/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -19,7 +19,7 @@ namespace TestClient.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
4
TestClient/Properties/Settings.Designer.cs
generated
4
TestClient/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -12,7 +12,7 @@ namespace TestClient.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>TestClient</RootNamespace>
|
||||
<AssemblyName>TestClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
@@ -22,6 +22,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -31,6 +32,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
||||
</startup>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using NSspi;
|
||||
|
||||
@@ -13,7 +9,7 @@ namespace TestProtocol
|
||||
public class CustomConnection
|
||||
{
|
||||
private Thread receiveThread;
|
||||
|
||||
|
||||
private Socket socket;
|
||||
|
||||
private bool running;
|
||||
@@ -24,7 +20,7 @@ namespace TestProtocol
|
||||
}
|
||||
|
||||
public delegate void ReceivedAction( Message message );
|
||||
|
||||
|
||||
public event ReceivedAction Received;
|
||||
|
||||
public event Action Disconnected;
|
||||
@@ -33,7 +29,7 @@ namespace TestProtocol
|
||||
{
|
||||
if( this.running )
|
||||
{
|
||||
throw new InvalidOperationException("Already running");
|
||||
throw new InvalidOperationException( "Already running" );
|
||||
}
|
||||
|
||||
this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
|
||||
@@ -65,7 +61,7 @@ namespace TestProtocol
|
||||
throw new InvalidOperationException( "Not connected" );
|
||||
}
|
||||
|
||||
byte[] outBuffer = new byte[ message.Data.Length + 8 ];
|
||||
byte[] outBuffer = new byte[message.Data.Length + 8];
|
||||
int position = 0;
|
||||
|
||||
ByteWriter.WriteInt32_BE( (int)message.Operation, outBuffer, position );
|
||||
@@ -97,10 +93,7 @@ namespace TestProtocol
|
||||
|
||||
try
|
||||
{
|
||||
if( this.Disconnected != null )
|
||||
{
|
||||
this.Disconnected();
|
||||
}
|
||||
this.Disconnected?.Invoke();
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
@@ -124,16 +117,15 @@ namespace TestProtocol
|
||||
// |--4 bytes--|--4 bytes--|---N--|
|
||||
// Every command is a TLV - | Operation | Length | Data |
|
||||
|
||||
|
||||
// Read the operation.
|
||||
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
||||
|
||||
// Check if we popped out of a receive call after we were shut down.
|
||||
if( this.running == false ) { break; }
|
||||
|
||||
|
||||
operation = (ProtocolOp)ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
||||
|
||||
// Read the length
|
||||
// Read the length
|
||||
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
||||
messageLength = ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
||||
|
||||
@@ -153,14 +145,13 @@ namespace TestProtocol
|
||||
remaining -= chunkLength;
|
||||
position += chunkLength;
|
||||
}
|
||||
|
||||
}
|
||||
catch( SocketException e )
|
||||
{
|
||||
if( e.SocketErrorCode == SocketError.ConnectionAborted ||
|
||||
e.SocketErrorCode == SocketError.Interrupted ||
|
||||
e.SocketErrorCode == SocketError.OperationAborted ||
|
||||
e.SocketErrorCode == SocketError.Shutdown ||
|
||||
e.SocketErrorCode == SocketError.Shutdown ||
|
||||
e.SocketErrorCode == SocketError.ConnectionReset )
|
||||
{
|
||||
// Shutting down.
|
||||
@@ -179,16 +170,15 @@ namespace TestProtocol
|
||||
byte[] dataCopy = new byte[messageLength];
|
||||
Array.Copy( readBuffer, 0, dataCopy, 0, messageLength );
|
||||
Message message = new Message( operation, dataCopy );
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
this.Received( message );
|
||||
}
|
||||
catch( Exception e )
|
||||
catch( Exception )
|
||||
{ }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ namespace TestProtocol
|
||||
|
||||
operation = (ProtocolOp)ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
||||
|
||||
// Read the length
|
||||
// Read the length
|
||||
this.readSocket.Receive( readBuffer, 4, SocketFlags.None );
|
||||
messageLength = ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
||||
|
||||
@@ -212,7 +212,6 @@ namespace TestProtocol
|
||||
catch( Exception )
|
||||
{ }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
@@ -225,5 +224,4 @@ namespace TestProtocol
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TestProtocol
|
||||
{
|
||||
public class Message
|
||||
{
|
||||
public Message(ProtocolOp op, byte[] data)
|
||||
public Message( ProtocolOp op, byte[] data )
|
||||
{
|
||||
this.Operation = op;
|
||||
this.Data = data;
|
||||
@@ -18,4 +14,4 @@ namespace TestProtocol
|
||||
|
||||
public byte[] Data { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle( "TestProtocol" )]
|
||||
@@ -14,8 +13,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTrademark( "" )]
|
||||
[assembly: AssemblyCulture( "" )]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible( false )]
|
||||
|
||||
@@ -25,12 +24,12 @@ using System.Runtime.InteropServices;
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion( "1.0.0.0" )]
|
||||
[assembly: AssemblyFileVersion( "1.0.0.0" )]
|
||||
[assembly: AssemblyFileVersion( "1.0.0.0" )]
|
||||
4
TestProtocol/Properties/Resources.Designer.cs
generated
4
TestProtocol/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -19,7 +19,7 @@ namespace TestProtocol.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
4
TestProtocol/Properties/Settings.Designer.cs
generated
4
TestProtocol/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -12,7 +12,7 @@ namespace TestProtocol.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TestProtocol
|
||||
{
|
||||
@@ -14,4 +10,4 @@ namespace TestProtocol
|
||||
EncryptedMessage = 3,
|
||||
SignedMessage = 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>TestProtocol</RootNamespace>
|
||||
<AssemblyName>TestProtocol</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
@@ -22,6 +22,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -31,6 +32,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
||||
</startup>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TestServer
|
||||
{
|
||||
static class Program
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
private static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault( false );
|
||||
Application.Run( new ServerForm() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle( "TestServer" )]
|
||||
@@ -14,8 +13,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTrademark( "" )]
|
||||
[assembly: AssemblyCulture( "" )]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible( false )]
|
||||
|
||||
@@ -25,12 +24,12 @@ using System.Runtime.InteropServices;
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion( "1.0.0.0" )]
|
||||
[assembly: AssemblyFileVersion( "1.0.0.0" )]
|
||||
[assembly: AssemblyFileVersion( "1.0.0.0" )]
|
||||
4
TestServer/Properties/Resources.Designer.cs
generated
4
TestServer/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -19,7 +19,7 @@ namespace TestServer.Properties {
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
4
TestServer/Properties/Settings.Designer.cs
generated
4
TestServer/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -12,7 +12,7 @@ namespace TestServer.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
3
TestServer/ServerForm.Designer.cs
generated
3
TestServer/ServerForm.Designer.cs
generated
@@ -170,7 +170,8 @@
|
||||
//
|
||||
// impersonateButton
|
||||
//
|
||||
this.impersonateButton.Location = new System.Drawing.Point(262, 350);
|
||||
this.impersonateButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.impersonateButton.Location = new System.Drawing.Point(262, 356);
|
||||
this.impersonateButton.Name = "impersonateButton";
|
||||
this.impersonateButton.Size = new System.Drawing.Size(116, 23);
|
||||
this.impersonateButton.TabIndex = 4;
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using NSspi;
|
||||
using NSspi.Contexts;
|
||||
using NSspi.Credentials;
|
||||
using TestProtocol;
|
||||
|
||||
namespace TestServer
|
||||
{
|
||||
using System.IO;
|
||||
using NSspi;
|
||||
using NSspi.Contexts;
|
||||
using NSspi.Credentials;
|
||||
|
||||
using Message = TestProtocol.Message;
|
||||
|
||||
public partial class ServerForm : Form
|
||||
{
|
||||
private ServerCredential serverCred;
|
||||
private ServerCurrentCredential serverCred;
|
||||
|
||||
private ServerContext serverContext;
|
||||
|
||||
@@ -35,16 +31,17 @@ namespace TestServer
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.serverCred = new ServerCredential( PackageNames.Negotiate );
|
||||
this.serverCred = new ServerCurrentCredential( PackageNames.Negotiate );
|
||||
|
||||
this.serverContext = new ServerContext(
|
||||
this.serverContext = new ServerContext(
|
||||
serverCred,
|
||||
ContextAttrib.AcceptIntegrity |
|
||||
ContextAttrib.ReplayDetect |
|
||||
ContextAttrib.SequenceDetect |
|
||||
ContextAttrib.MutualAuth |
|
||||
ContextAttrib.Delegate |
|
||||
ContextAttrib.Confidentiality
|
||||
ContextAttrib.AcceptIntegrity |
|
||||
ContextAttrib.ReplayDetect |
|
||||
ContextAttrib.SequenceDetect |
|
||||
ContextAttrib.MutualAuth |
|
||||
ContextAttrib.Delegate |
|
||||
ContextAttrib.Confidentiality,
|
||||
true
|
||||
);
|
||||
|
||||
this.server = new CustomServer();
|
||||
@@ -129,11 +126,15 @@ namespace TestServer
|
||||
{
|
||||
MessageBox.Show( "Starting impersonation: " + Environment.UserName );
|
||||
|
||||
FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory) + @"\test.txt" );
|
||||
var directory = Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory );
|
||||
|
||||
Directory.CreateDirectory( directory );
|
||||
|
||||
FileStream stream = File.Create( directory + @"\test.txt" );
|
||||
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
|
||||
|
||||
writer.WriteLine( "Hello world." );
|
||||
|
||||
|
||||
writer.Close();
|
||||
stream.Close();
|
||||
}
|
||||
@@ -150,7 +151,6 @@ namespace TestServer
|
||||
this.signButton.Enabled = this.connected;
|
||||
}
|
||||
|
||||
|
||||
private void server_Received( Message message )
|
||||
{
|
||||
if( message.Operation == ProtocolOp.ClientToken )
|
||||
@@ -171,13 +171,38 @@ namespace TestServer
|
||||
}
|
||||
}
|
||||
|
||||
private void InitComplete()
|
||||
{
|
||||
UpdateButtons();
|
||||
this.clientUsernameTextBox.Text = serverContext.ContextUserName;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
var remoteId = this.serverContext.GetRemoteIdentity();
|
||||
|
||||
builder.AppendLine( "Client identity information:" );
|
||||
builder.AppendLine( " - Name: " + remoteId.Name );
|
||||
|
||||
var windowsId = remoteId as WindowsIdentity;
|
||||
|
||||
if( windowsId != null )
|
||||
{
|
||||
builder.AppendLine( " - User SID: " + windowsId.User.Value );
|
||||
|
||||
foreach( var claim in windowsId.Claims )
|
||||
{
|
||||
builder.AppendLine( " - " + claim.ToString() );
|
||||
}
|
||||
}
|
||||
|
||||
this.receivedTextbox.AppendText( builder.ToString() );
|
||||
}
|
||||
|
||||
private void server_Disconnected()
|
||||
{
|
||||
this.running = true;
|
||||
this.initializing = true;
|
||||
this.connected = false;
|
||||
|
||||
|
||||
this.serverContext.Dispose();
|
||||
this.serverContext = new ServerContext(
|
||||
serverCred,
|
||||
@@ -189,14 +214,13 @@ namespace TestServer
|
||||
ContextAttrib.Confidentiality
|
||||
);
|
||||
|
||||
this.BeginInvoke( (Action)delegate()
|
||||
this.BeginInvoke( (Action)delegate ()
|
||||
{
|
||||
UpdateButtons();
|
||||
this.clientUsernameTextBox.Text = "";
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
private void HandleInit( Message message )
|
||||
{
|
||||
byte[] nextToken;
|
||||
@@ -218,38 +242,33 @@ namespace TestServer
|
||||
this.initializing = false;
|
||||
this.connected = true;
|
||||
|
||||
this.Invoke( (Action)delegate()
|
||||
{
|
||||
UpdateButtons();
|
||||
this.clientUsernameTextBox.Text = serverContext.ContextUserName;
|
||||
} );
|
||||
this.Invoke( (Action)InitComplete );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Invoke( (Action)delegate()
|
||||
this.Invoke( (Action)delegate ()
|
||||
{
|
||||
MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEncrypted( Message message )
|
||||
{
|
||||
this.Invoke( (Action)delegate()
|
||||
this.Invoke( (Action)delegate ()
|
||||
{
|
||||
byte[] plainText = this.serverContext.Decrypt( message.Data );
|
||||
string text = Encoding.UTF8.GetString( plainText );
|
||||
|
||||
|
||||
this.receivedTextbox.Text += "Received encrypted message from client:\r\n" + text + "\r\n";
|
||||
} );
|
||||
}
|
||||
|
||||
private void HandleSigned( Message message )
|
||||
{
|
||||
this.Invoke( (Action)delegate()
|
||||
this.Invoke( (Action)delegate ()
|
||||
{
|
||||
byte[] plainText;
|
||||
|
||||
@@ -268,11 +287,10 @@ namespace TestServer
|
||||
|
||||
private void HandleUnknown( Message message )
|
||||
{
|
||||
this.Invoke( (Action)delegate()
|
||||
this.Invoke( (Action)delegate ()
|
||||
{
|
||||
MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>TestServer</RootNamespace>
|
||||
<AssemblyName>TestServer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
@@ -22,6 +22,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -31,6 +32,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
## Downloads ##
|
||||
|
||||
The latest release of NSspi is v0.1.1.
|
||||
The latest release of NSspi is v0.3.1, released 5-Aug-2019.
|
||||
|
||||
* [Source](https://github.com/antiduh/nsspi/archive/0.1.1.zip)
|
||||
* [Binaries](https://github.com/antiduh/nsspi/releases/download/0.1.1/nsspi-0.1.1-bin.zip)
|
||||
Version 0.3.1 adds support to obtain an IIdentity/WindowsPrinciple representing the remote connection. This is useful for servers that wish to query the properties on the principle, such as claims.
|
||||
|
||||
* [Source](https://github.com/antiduh/nsspi/archive/0.3.1.zip)
|
||||
* [Nuget package](https://www.nuget.org/packages/NSspi)
|
||||
|
||||
You can also browse the list of [releases](https://github.com/antiduh/nsspi/releases).
|
||||
@@ -11,7 +12,7 @@ You can also browse the list of [releases](https://github.com/antiduh/nsspi/rele
|
||||
|
||||
|
||||
## Introduction ##
|
||||
This projects provides a C# / .Net interface to the Windows Integrated Authentication API, better known as SSPI (Security Service Provider Interface). This allows a custom client / server system to authenticate users using their existing logon credentials. This allows a developer to provide Single-Sign-On in their application.
|
||||
This project provides a C# / .Net interface to the Windows Integrated Authentication API, better known as SSPI (Security Service Provider Interface). This allows a custom client / server system to authenticate users using their existing logon credentials. This allows a developer to provide Single-Sign-On in their application.
|
||||
|
||||
## Overview ##
|
||||
The API provides raw access to authentication tokens so that authentication can be easily integrated into any networking system - you can send the tokens over a socket, a remoting interface, or heck even a serial port if you want; they're just bytes. Clients and servers may exchange encrypted and signed messages, and the server can perform client impersonation.
|
||||
|
||||
Reference in New Issue
Block a user