47 Commits
0.1.1 ... 0.30

Author SHA1 Message Date
Kevin Thompson
9cd6edbeb7 Added the project license to the package information. 2019-06-16 21:53:52 -04:00
Kevin Thompson
ad88537c14 Updated copyright year. 2019-06-16 21:53:01 -04:00
Kevin Thompson
2611d94033 Added strong-name signing to the library. 2019-06-16 17:48:27 -04:00
Kevin Thompson
f892e1c93f Bumped the version number to 0.3.0.0; enabled output of docs. 2019-06-16 17:25:59 -04:00
Kevin Thompson
91f6a680cf Improved code style. 2019-06-16 17:24:43 -04:00
Kevin Thompson
52322afeaa Updated comments. 2019-06-16 17:22:50 -04:00
Kevin Thompson
002da1559b Fixed code style. 2019-06-16 17:22:21 -04:00
Kevin Thompson
01ad97b272 Removed unused code. 2019-06-16 17:21:14 -04:00
Kevin Thompson
ac4217d9d4 Updated comments. 2019-06-16 16:57:43 -04:00
Kevin Thompson
bbb7c7a060 Improved the impersonation revert process.
The Dispose(bool) method will still act even if finalizing, but it armors its access to the server to ensure that it doesn't accidentally cause a nullref trying to revert itself.
2019-06-16 16:57:23 -04:00
Kevin Thompson
4bd2ad0024 Merge pull request #19 from StefanOssendorf/feature/net-standard
Nsspi switched to SDK project style; targets .Net Framework 4.0 and .Net Standard 2.0. Demo projects unchanged.
2019-06-16 11:00:33 -04:00
Stefan Ossendorf
3ccdcc701e Nsspi targets now Net4.0 and .NetStandard2.0
Nsspi now multi targets .Net 4.0 and .NetStandard 2.0.
Dependencies are included based on framework.
2019-05-31 09:12:53 +02:00
Stefan Ossendorf
923d70195d Nsspi target framework changed to .NetStandard2.0
Nsspi targets now .NetStandard2.0
Other projects now targets .net4 .6.1
Nuspec file removed and nuget file will now be created on each build (new capaibility of VS17 used for that)
Assemblyinfo resieds now within csproj of nsspi project
ReSharpher folder added to gitignore
2019-05-30 14:46:03 +02:00
Kevin Thompson
56ca05b230 Fixed typo 2019-02-12 01:17:03 -05:00
Kevin Thompson
82eaae0570 Announced the release of v0.2.1. 2018-09-23 10:53:18 -04:00
Kevin Thompson
6bf95f46ee Updated version information to v0.2.1 2018-09-23 10:44:43 -04:00
Kevin Thompson
5c63105acf Merge pull request #12 from antiduh/pr/11
Pr/11 Integrate @SteveSyfuhs Thread.CurrentPrinciple changes
2018-04-01 18:10:28 -04:00
Kevin Thompson
19716405b8 Moved SetThreadIdentity into the ServerContext
The ImpersonationHandle class should probably stay as bare as possible since it's provided to the caller and we don't want to expose anything more than we need. Since the ServerContext is capable of performing this as a private method, move it there.
Updated the comments and variable names on the constructor to better indicate what exactly the option does, especially since modification of this property seems to be such a touchy subject.
2018-04-01 18:05:00 -04:00
Steve Syfuhs
f0820875c3 Fixed enum value. Any actual unicode strings passed in will only use the first character because the 0 byte after the first character is treated as a terminator.
Added ability to set the current thread principal so it's inline with the actual security context.
2018-03-30 11:40:37 -07:00
Kevin Thompson
8355a6b821 Fixed binaries url 2017-10-20 01:52:33 -04:00
Kevin Thompson
4d79f1b5db Announced v0.2.0 release 2017-10-20 01:46:33 -04:00
Kevin Thompson
aef74fe8aa Default to VS2015. 2017-10-20 01:25:49 -04:00
Kevin Thompson
37a7881d25 Updated version declarations to v0.2.0, to reflect the new support for username/password authentication plus the minor incompatibility introduced with the updated design. 2017-10-20 01:25:36 -04:00
Kevin Thompson
9350412fb6 Updated the svn-ignore properties. 2017-09-24 02:41:00 -04:00
Kevin Thompson
6a5e6056a7 Added password authentication support.
Added the ability to acquire a valid credential by providing a username/password combination.
2017-09-24 02:39:49 -04:00
Kevin Thompson
c6c0ac623e Code cleanup.
Fixed comment and code style; removed unnecessary initialization of variable.
2017-09-24 02:10:00 -04:00
Kevin Thompson
c07abdaa62 Comments. 2017-09-24 02:02:10 -04:00
Kevin Thompson
f2d4541bab Renamed Client/ServerCredential.
The credential implementations should indicate in their name that they are implementations of the 'current' credential (acquired from the login running the process).
2017-09-24 01:59:34 -04:00
Kevin Thompson
0eb8ff49f2 Fixed ClientContext and ServerContext constructors.
Changed the contexts to take in any Credential implementation, instead of requiring client- or server-specific credentials.
2017-09-24 01:56:36 -04:00
Kevin Thompson
3b189d2865 Code cleanup
Fixed code style using CodeMaid.
2017-09-24 01:52:45 -04:00
Kevin Thompson
6ff68d8812 Merge pull request #8 from mcgov/master
Adding QuerySessionKey, as well as QueryContextAttributes and SafeQue…
2017-09-23 15:00:00 -04:00
Matthew McGovern
e631d77f01 Adding QuerySessionKey, as well as QueryContextAttributes and SafeQueryContextAttributes 2017-09-22 09:21:48 -07:00
Kevin Thompson
4e629a71b2 Changed the csproj to output the documentation xml file 2017-05-01 10:10:32 -04:00
Kevin Thompson
8db4b6d8a5 Documented release 0.1.3 in the readme 2017-05-01 10:06:00 -04:00
Kevin Thompson
6b008f0e72 Bumped version number to 0.1.3
Needed to rebuild the nuget package due to a compilation mistake.
2017-05-01 09:59:15 -04:00
Kevin Thompson
8e68283df6 Added the nuspec file to the project. 2017-05-01 09:56:14 -04:00
Kevin Thompson
9862ee4aa4 Bumped version number to 0.1.2
Includes fix from #6.
2017-05-01 09:55:57 -04:00
Kevin Thompson
5cb0735213 Merge pull request #6 from matt-sullivan/master
Fix SSPIException serialization bug due to typo.
2017-04-30 16:39:25 -04:00
Matt Sullivan
5018ba17c2 Fix SSPIException serialization
It was failing due to a typo in a field name.
2017-05-01 00:10:56 +10:00
Kevin Thompson
5eeb3f874b Merge branch 'master' of https://github.com/antiduh/nsspi 2017-03-01 10:24:27 -05:00
Kevin Thompson
91f18604fe Added language declaration to nuspec 2017-01-20 16:36:24 -05:00
Kevin Thompson
c3b560cd17 Added link to nuget package. 2017-01-20 16:29:56 -05:00
Kevin Thompson
e7d93e0732 Added nuget spec for the core library 2017-01-20 16:20:02 -05:00
Kevin Thompson
1684280216 Removed unneceessary references
Got rid of dependencies that NSspi.csproj doesn't need.
2017-01-20 16:05:08 -05:00
Kevin Thompson
e93e20fa7f Added gitignore files
Marked all derived content directories as ignored.
2017-01-20 16:03:59 -05:00
Kevin Thompson
7a42da7f2c Removed old text-only readme file
Superseded by the markdown version.
2015-06-03 11:16:52 -04:00
Kevin Thompson
f8400caea6 Created a better readme file
Added links to the current release of source and binaries, a very-obvious link to to the 'releases' tab, added sectioning.
2015-06-03 11:16:07 -04:00
76 changed files with 1069 additions and 840 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.vs
/_ReSharper.Caches

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014, Kevin Thompson Copyright (c) 2019, Kevin Thompson
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,8 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012 # Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}"

2
NSspi/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bin
obj

View File

@@ -1,9 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {
@@ -37,8 +32,7 @@ namespace NSspi
buffer[position + 0] = (byte)( value >> 24 ); buffer[position + 0] = (byte)( value >> 24 );
buffer[position + 1] = (byte)( value >> 16 ); buffer[position + 1] = (byte)( value >> 16 );
buffer[position + 2] = (byte)( value >> 8 ); buffer[position + 2] = (byte)( value >> 8 );
buffer[position + 3] = (byte)( value); buffer[position + 3] = (byte)( value );
} }
/// <summary> /// <summary>

View File

@@ -1,9 +1,4 @@
using System; 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.Buffers;
using NSspi.Credentials; using NSspi.Credentials;
@@ -33,7 +28,7 @@ namespace NSspi.Contexts
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the /// <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 /// context once it is established. If a context cannot be established that satisfies the indicated
/// properties, the context initialization is aborted.</param> /// 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 ) : base( cred )
{ {
this.serverPrinc = serverPrinc; this.serverPrinc = serverPrinc;
@@ -90,12 +85,12 @@ namespace NSspi.Contexts
// The security package tells us how big its biggest token will be. We'll allocate a buffer // 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. // that size, and it'll tell us how much it used.
outTokenBuffer = new SecureBuffer( outTokenBuffer = new SecureBuffer(
new byte[ this.Credential.PackageInfo.MaxTokenLength ], new byte[this.Credential.PackageInfo.MaxTokenLength],
BufferType.Token BufferType.Token
); );
serverBuffer = null; serverBuffer = null;
if ( serverToken != null ) if( serverToken != null )
{ {
serverBuffer = new SecureBuffer( serverToken, BufferType.Token ); serverBuffer = new SecureBuffer( serverToken, BufferType.Token );
} }
@@ -115,9 +110,9 @@ namespace NSspi.Contexts
// Windows, 128 bits on 64-bit Windows. // 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 // - 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. // 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( status = ContextNativeMethods.InitializeSecurityContext_1(
ref this.Credential.Handle.rawHandle, ref this.Credential.Handle.rawHandle,
@@ -136,7 +131,7 @@ namespace NSspi.Contexts
} }
else else
{ {
using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) ) using( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
{ {
status = ContextNativeMethods.InitializeSecurityContext_2( status = ContextNativeMethods.InitializeSecurityContext_2(
ref this.Credential.Handle.rawHandle, ref this.Credential.Handle.rawHandle,

View File

@@ -1,12 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using NSspi.Buffers; using NSspi.Buffers;
using NSspi.Contexts;
using NSspi.Credentials; using NSspi.Credentials;
namespace NSspi.Contexts namespace NSspi.Contexts
@@ -257,7 +252,7 @@ namespace NSspi.Contexts
paddingLength = ByteWriter.ReadInt16_BE( input, position ); paddingLength = ByteWriter.ReadInt16_BE( input, position );
position += 2; 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." ); throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
} }
@@ -296,8 +291,7 @@ namespace NSspi.Contexts
} }
// else there was no padding. // else there was no padding.
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
using( adapter = new SecureBufferAdapter( new [] { trailerBuffer, dataBuffer, paddingBuffer } ) )
{ {
status = ContextNativeMethods.SafeDecryptMessage( status = ContextNativeMethods.SafeDecryptMessage(
this.ContextHandle, this.ContextHandle,
@@ -348,7 +342,7 @@ namespace NSspi.Contexts
Array.Copy( message, dataBuffer.Buffer, message.Length ); Array.Copy( message, dataBuffer.Buffer, message.Length );
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) ) using( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
{ {
status = ContextNativeMethods.SafeMakeSignature( status = ContextNativeMethods.SafeMakeSignature(
this.ContextHandle, this.ContextHandle,
@@ -358,7 +352,7 @@ namespace NSspi.Contexts
); );
} }
if ( status != SecurityStatus.OK ) if( status != SecurityStatus.OK )
{ {
throw new SSPIException( "Failed to create message signature.", status ); throw new SSPIException( "Failed to create message signature.", status );
} }
@@ -389,6 +383,35 @@ namespace NSspi.Contexts
return outMessage; 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> /// <summary>
/// Verifies the signature of a signed message /// Verifies the signature of a signed message
/// </summary> /// </summary>
@@ -415,7 +438,7 @@ namespace NSspi.Contexts
sizes = QueryBufferSizes(); 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" ); throw new ArgumentException( "Input message is too small to possibly fit a valid message" );
} }
@@ -430,7 +453,7 @@ namespace NSspi.Contexts
sigLen = ByteWriter.ReadInt16_BE( signedMessage, position ); sigLen = ByteWriter.ReadInt16_BE( signedMessage, position );
position += 2; 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." ); throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
} }
@@ -443,7 +466,7 @@ namespace NSspi.Contexts
Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen ); Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen );
position += sigLen; position += sigLen;
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) ) using( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
{ {
status = ContextNativeMethods.SafeVerifySignature( status = ContextNativeMethods.SafeVerifySignature(
this.ContextHandle, this.ContextHandle,
@@ -453,12 +476,12 @@ namespace NSspi.Contexts
); );
} }
if ( status == SecurityStatus.OK ) if( status == SecurityStatus.OK )
{ {
origMessage = dataBuffer.Buffer; origMessage = dataBuffer.Buffer;
return true; return true;
} }
else if ( status == SecurityStatus.MessageAltered || else if( status == SecurityStatus.MessageAltered ||
status == SecurityStatus.OutOfSequence ) status == SecurityStatus.OutOfSequence )
{ {
origMessage = null; origMessage = null;
@@ -485,9 +508,9 @@ namespace NSspi.Contexts
{ {
this.ContextHandle.DangerousAddRef( ref gotRef ); this.ContextHandle.DangerousAddRef( ref gotRef );
} }
catch ( Exception ) catch( Exception )
{ {
if ( gotRef ) if( gotRef )
{ {
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -497,7 +520,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if( gotRef )
{ {
status = ContextNativeMethods.QueryContextAttributes_Sizes( status = ContextNativeMethods.QueryContextAttributes_Sizes(
ref this.ContextHandle.rawHandle, ref this.ContextHandle.rawHandle,
@@ -521,7 +544,7 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
/// <param name="attrib">The string-valued attribute to query.</param> /// <param name="attrib">The string-valued attribute to query.</param>
/// <returns></returns> /// <returns></returns>
private string QueryContextString(ContextQueryAttrib attrib) private string QueryContextString( ContextQueryAttrib attrib )
{ {
SecPkgContext_String stringAttrib; SecPkgContext_String stringAttrib;
SecurityStatus status = SecurityStatus.InternalError; SecurityStatus status = SecurityStatus.InternalError;
@@ -540,9 +563,9 @@ namespace NSspi.Contexts
{ {
this.ContextHandle.DangerousAddRef( ref gotRef ); this.ContextHandle.DangerousAddRef( ref gotRef );
} }
catch ( Exception ) catch( Exception )
{ {
if ( gotRef ) if( gotRef )
{ {
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -551,7 +574,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if( gotRef )
{ {
status = ContextNativeMethods.QueryContextAttributes_String( status = ContextNativeMethods.QueryContextAttributes_String(
ref this.ContextHandle.rawHandle, ref this.ContextHandle.rawHandle,
@@ -561,7 +584,7 @@ namespace NSspi.Contexts
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
if ( status == SecurityStatus.OK ) if( status == SecurityStatus.OK )
{ {
result = Marshal.PtrToStringUni( stringAttrib.StringResult ); result = Marshal.PtrToStringUni( stringAttrib.StringResult );
ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult ); ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult );

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
@@ -36,7 +32,6 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
MutualAuth = 0x00000002, MutualAuth = 0x00000002,
/// <summary> /// <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. /// message support functionality.
@@ -121,7 +116,16 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
AcceptIntegrity = 0x00020000, 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, 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, AcceptIdentify = 0x00080000,
/// <summary> /// <summary>

View File

@@ -1,13 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using NSspi.Buffers; using NSspi.Buffers;
using NSspi.Contexts;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
@@ -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( internal static extern SecurityStatus AcceptSecurityContext_1(
ref RawSspiHandle credHandle, ref RawSspiHandle credHandle,
IntPtr oldContextHandle, IntPtr oldContextHandle,
@@ -58,7 +53,6 @@ namespace NSspi.Contexts
ref TimeStamp expiry ref TimeStamp expiry
); );
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus AcceptSecurityContext_2( internal static extern SecurityStatus AcceptSecurityContext_2(
ref RawSspiHandle credHandle, ref RawSspiHandle credHandle,
@@ -72,7 +66,6 @@ namespace NSspi.Contexts
ref TimeStamp expiry ref TimeStamp expiry
); );
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus InitializeSecurityContext_1( internal static extern SecurityStatus InitializeSecurityContext_1(
ref RawSspiHandle credentialHandle, ref RawSspiHandle credentialHandle,
@@ -89,7 +82,6 @@ namespace NSspi.Contexts
ref TimeStamp expiry ref TimeStamp expiry
); );
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus InitializeSecurityContext_2( internal static extern SecurityStatus InitializeSecurityContext_2(
ref RawSspiHandle credentialHandle, ref RawSspiHandle credentialHandle,
@@ -106,12 +98,11 @@ namespace NSspi.Contexts
ref TimeStamp expiry ref TimeStamp expiry
); );
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle ); 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 )] [DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus EncryptMessage( internal static extern SecurityStatus EncryptMessage(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
@@ -155,7 +146,7 @@ namespace NSspi.Contexts
ref SecPkgContext_Sizes sizes ref SecPkgContext_Sizes sizes
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus QueryContextAttributes_String( internal static extern SecurityStatus QueryContextAttributes_String(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
@@ -163,11 +154,18 @@ namespace NSspi.Contexts
ref SecPkgContext_String names 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 )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle ); internal static extern SecurityStatus FreeContextBuffer( IntPtr handle );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle ); internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle );
@@ -176,6 +174,72 @@ namespace NSspi.Contexts
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle ); internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
[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> /// <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. /// performed in a proper CER.
@@ -199,9 +263,9 @@ namespace NSspi.Contexts
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef( ref gotRef );
} }
catch ( Exception ) catch( Exception )
{ {
if ( gotRef ) if( gotRef )
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -211,7 +275,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if( gotRef )
{ {
status = ContextNativeMethods.EncryptMessage( status = ContextNativeMethods.EncryptMessage(
ref handle.rawHandle, ref handle.rawHandle,
@@ -301,9 +365,9 @@ namespace NSspi.Contexts
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef( ref gotRef );
} }
catch ( Exception ) catch( Exception )
{ {
if ( gotRef ) if( gotRef )
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -313,7 +377,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if( gotRef )
{ {
status = ContextNativeMethods.MakeSignature( status = ContextNativeMethods.MakeSignature(
ref handle.rawHandle, ref handle.rawHandle,
@@ -352,9 +416,9 @@ namespace NSspi.Contexts
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef( ref gotRef );
} }
catch ( Exception ) catch( Exception )
{ {
if ( gotRef ) if( gotRef )
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -364,7 +428,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if( gotRef )
{ {
status = ContextNativeMethods.VerifySignature( status = ContextNativeMethods.VerifySignature(
ref handle.rawHandle, ref handle.rawHandle,

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Contexts 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. /// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
/// </remarks> /// </remarks>
Authority = 6, 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
} }
} }

View File

@@ -1,8 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Security.Principal;
using System.Linq; using System.Threading;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
@@ -20,26 +18,30 @@ namespace NSspi.Contexts
/// </remarks> /// </remarks>
public class ImpersonationHandle : IDisposable public class ImpersonationHandle : IDisposable
{ {
private readonly ServerContext server;
private bool disposed; private bool disposed;
private ServerContext server;
/// <summary> /// <summary>
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation. /// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
/// </summary> /// </summary>
/// <param name="server">The server context that is performing impersonation.</param> /// <param name="server">The server context that is performing impersonation.</param>
internal ImpersonationHandle(ServerContext server) internal ImpersonationHandle( ServerContext server )
{ {
this.server = server; this.server = server;
this.disposed = false; this.disposed = false;
} }
/// <summary>
/// Finalizes the ImpersonationHandle by reverting the impersonation.
/// </summary>
~ImpersonationHandle() ~ImpersonationHandle()
{ {
Dispose( false ); Dispose( false );
} }
/// <summary> /// <summary>
/// Reverts the impersonation. /// Reverts impersonation.
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
@@ -47,13 +49,28 @@ namespace NSspi.Contexts
GC.SuppressFinalize( this ); 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();
}
} }
} }
} }
} }

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Contexts namespace NSspi.Contexts
{ {
@@ -12,10 +8,17 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
public class SafeContextHandle : SafeSspiHandle public class SafeContextHandle : SafeSspiHandle
{ {
/// <summary>
/// Initializes a new instance of the <see cref="SafeContextHandle"/> class.
/// </summary>
public SafeContextHandle() public SafeContextHandle()
: base() : base()
{ } { }
/// <summary>
/// Releases the safe context handle.
/// </summary>
/// <returns></returns>
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {

View File

@@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Security.Principal;
using System.Threading.Tasks; using System.Threading;
using NSspi.Buffers; using NSspi.Buffers;
using NSspi.Credentials; using NSspi.Credentials;
@@ -14,20 +12,27 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
public class ServerContext : Context public class ServerContext : Context
{ {
private ContextAttrib requestedAttribs; private readonly ContextAttrib requestedAttribs;
private ContextAttrib finalAttribs; private readonly bool impersonationSetsThreadPrinciple;
private ContextAttrib finalAttribs;
private bool impersonating; private bool impersonating;
/// <summary> /// <summary>
/// Performs basic initialization of a new instance of the ServerContext class. The ServerContext /// Performs basic initialization of a new instance of the ServerContext class. The
/// is not ready for message manipulation until a security context has been established with a client. /// ServerContext is not ready for message manipulation until a security context has been
/// established with a client.
/// </summary> /// </summary>
/// <param name="cred"></param> /// <param name="cred"></param>
/// <param name="requestedAttribs"></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.requestedAttribs = requestedAttribs;
this.impersonationSetsThreadPrinciple = impersonationSetsThreadPrinciple;
this.finalAttribs = ContextAttrib.Zero; this.finalAttribs = ContextAttrib.Zero;
this.impersonating = false; this.impersonating = false;
@@ -90,13 +95,13 @@ namespace NSspi.Contexts
clientBuffer = new SecureBuffer( clientToken, BufferType.Token ); clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
outBuffer = new SecureBuffer( outBuffer = new SecureBuffer(
new byte[ this.Credential.PackageInfo.MaxTokenLength ], new byte[this.Credential.PackageInfo.MaxTokenLength],
BufferType.Token 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 ) if( this.ContextHandle.IsInvalid )
{ {
@@ -125,19 +130,15 @@ namespace NSspi.Contexts
ref this.finalAttribs, ref this.finalAttribs,
ref rawExpiry ref rawExpiry
); );
} }
} }
} }
if ( status == SecurityStatus.OK ) if( status == SecurityStatus.OK )
{ {
nextToken = null;
base.Initialize( rawExpiry.ToDateTime() ); base.Initialize( rawExpiry.ToDateTime() );
if ( outBuffer.Length != 0 ) if( outBuffer.Length != 0 )
{ {
nextToken = new byte[outBuffer.Length]; nextToken = new byte[outBuffer.Length];
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length ); Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
@@ -147,7 +148,7 @@ namespace NSspi.Contexts
nextToken = null; nextToken = null;
} }
} }
else if ( status == SecurityStatus.ContinueNeeded ) else if( status == SecurityStatus.ContinueNeeded )
{ {
nextToken = new byte[outBuffer.Length]; nextToken = new byte[outBuffer.Length];
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length ); Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
@@ -226,7 +227,7 @@ namespace NSspi.Contexts
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
this.impersonating = true; this.impersonating = status == SecurityStatus.OK;
} }
} }
@@ -243,6 +244,11 @@ namespace NSspi.Contexts
throw new SSPIException( "Failed to impersonate the client", status ); throw new SSPIException( "Failed to impersonate the client", status );
} }
if( this.impersonating && this.impersonationSetsThreadPrinciple )
{
SetThreadPrinciple();
}
return handle; 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 ) protected override void Dispose( bool disposing )
{ {
// We were disposed while impersonating. This means that the consumer that is currently holding // We were disposed while impersonating. This means that the consumer that is currently holding
@@ -305,5 +315,15 @@ namespace NSspi.Contexts
base.Dispose( disposing ); base.Dispose( disposing );
} }
/// <summary>
/// Set the current thread security context to the impersonated identity.
/// </summary>
private void SetThreadPrinciple()
{
Thread.CurrentPrincipal = new WindowsPrincipal(
WindowsIdentity.GetCurrent( TokenAccessLevels.AllAccess )
);
}
} }
} }

View 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
}
}

View File

@@ -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 )
{
}
}
}

View 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 )
{
}
}
}

View File

@@ -1,13 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using NSspi.Credentials;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {
@@ -16,16 +9,16 @@ namespace NSspi.Credentials
/// </summary> /// </summary>
public class Credential : IDisposable public class Credential : IDisposable
{ {
/// <summary>
/// The name of the security package that controls the credential.
/// </summary>
private readonly string securityPackage;
/// <summary> /// <summary>
/// Whether the Credential has been disposed. /// Whether the Credential has been disposed.
/// </summary> /// </summary>
private bool disposed; private bool disposed;
/// <summary>
/// The name of the security package that controls the credential.
/// </summary>
private string securityPackage;
/// <summary> /// <summary>
/// A safe handle to the credential's handle. /// A safe handle to the credential's handle.
/// </summary> /// </summary>
@@ -42,11 +35,10 @@ namespace NSspi.Credentials
/// <param name="package">The security package to acquire the credential from.</param> /// <param name="package">The security package to acquire the credential from.</param>
public Credential( string package ) public Credential( string package )
{ {
this.disposed = false;
this.securityPackage = package; this.securityPackage = package;
this.disposed = false;
this.expiry = DateTime.MinValue; this.expiry = DateTime.MinValue;
this.PackageInfo = PackageSupport.GetPackageCapabilities( this.SecurityPackage ); this.PackageInfo = PackageSupport.GetPackageCapabilities( this.SecurityPackage );
} }
@@ -185,11 +177,15 @@ namespace NSspi.Credentials
GC.SuppressFinalize( this ); GC.SuppressFinalize( this );
} }
/// <summary>
/// Releases all resources associted with the credential.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose( bool disposing ) protected virtual void Dispose( bool disposing )
{ {
if ( this.disposed == false ) if( this.disposed == false )
{ {
if ( disposing ) if( disposing )
{ {
this.safeCredHandle.Dispose(); this.safeCredHandle.Dispose();
} }

View File

@@ -1,17 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using NSspi.Credentials;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {
internal static class CredentialNativeMethods internal static class CredentialNativeMethods
{ {
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail)] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus AcquireCredentialsHandle( internal static extern SecurityStatus AcquireCredentialsHandle(
string principleName, string principleName,
@@ -25,13 +20,27 @@ namespace NSspi.Credentials
ref TimeStamp expiry 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 )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus FreeCredentialsHandle( internal static extern SecurityStatus FreeCredentialsHandle(
ref RawSspiHandle credentialHandle ref RawSspiHandle credentialHandle
); );
/// <summary> /// <summary>
/// The overload of the QueryCredentialsAttribute method that is used for querying the name attribute. /// 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 /// In this call, it takes a void* to a structure that contains a wide char pointer. The wide character

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {
@@ -57,13 +53,12 @@ namespace NSspi.Credentials
); );
} }
if ( status != SecurityStatus.OK ) if( status != SecurityStatus.OK )
{ {
throw new SSPIException( "Failed to call AcquireCredentialHandle", status ); throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
} }
this.Expiry = rawExpiry.ToDateTime(); this.Expiry = rawExpiry.ToDateTime();
} }
} }
} }

View 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();
}
}
}

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {
@@ -12,10 +8,17 @@ namespace NSspi.Credentials
/// </summary> /// </summary>
public class SafeCredentialHandle : SafeSspiHandle public class SafeCredentialHandle : SafeSspiHandle
{ {
/// <summary>
/// Initializes a new instance of the <see cref="SafeCredentialHandle"/> class.
/// </summary>
public SafeCredentialHandle() public SafeCredentialHandle()
: base() : base()
{ } { }
/// <summary>
/// Releases the resources held by the credential handle.
/// </summary>
/// <returns></returns>
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {
@@ -28,5 +31,4 @@ namespace NSspi.Credentials
return status == SecurityStatus.OK; return status == SecurityStatus.OK;
} }
} }
} }

View File

@@ -1,23 +1,19 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Credentials namespace NSspi.Credentials
{ {
/// <summary> /// <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> /// </summary>
public class ServerCredential : CurrentCredential public class ServerCurrentCredential : CurrentCredential
{ {
/// <summary> /// <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. /// the current thread's security context.
/// </summary> /// </summary>
/// <param name="package">The name of the security package to obtain credentials from.</param> /// <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 ) : base( package, CredentialUse.Inbound )
{ {
} }

View File

@@ -1,24 +1,40 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
namespace NSspi namespace NSspi
{ {
/// <summary>
/// Tags an enumeration member with a string that can be programmatically accessed.
/// </summary>
[AttributeUsage( AttributeTargets.Field )] [AttributeUsage( AttributeTargets.Field )]
public class EnumStringAttribute : Attribute 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 ) public EnumStringAttribute( string text )
{ {
this.Text = text; this.Text = text;
} }
/// <summary>
/// Gets the string associated with the enumeration member.
/// </summary>
public string Text { get; private set; } 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 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 ) public static string ToText( Enum value )
{ {
FieldInfo field = value.GetType().GetField( value.ToString() ); 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 ) public static T FromText<T>( string text )
{ {
FieldInfo[] fields = typeof( T ).GetFields(); FieldInfo[] fields = typeof( T ).GetFields();

View File

@@ -1,96 +1,33 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<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')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4B4CD933-BF62-4F92-B8FA-6771758C5197}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NSspi</RootNamespace> <RootNamespace>NSspi</RootNamespace>
<AssemblyName>NSspi</AssemblyName> <AssemblyName>NSspi</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<FileAlignment>512</FileAlignment> <Authors>Kevin Thompson</Authors>
<TargetFrameworkProfile /> <PackageReleaseNotes>Adds multi-targetting to support .Net Standard 2.0.</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/antiduh/nsspi</PackageProjectUrl>
<Version>0.3.0.0</Version>
<SignAssembly>true</SignAssembly>
<DelaySign>false</DelaySign>
<AssemblyOriginatorKeyFile>nsspi key.snk</AssemblyOriginatorKeyFile>
<PackageLicenseFile>License.txt</PackageLicenseFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DocumentationFile>NSspi.xml</DocumentationFile>
<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>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DebugType>pdbonly</DebugType> <DocumentationFile>NSspi.xml</DocumentationFile>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\NSspi.XML</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<StartupObject> <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
</StartupObject> <PackageReference Include="System.Security.Principal.Windows" Version="4.5.1" />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ByteWriter.cs" /> <None Include="..\License.txt">
<Compile Include="Contexts\ClientContext.cs" /> <Pack>True</Pack>
<Compile Include="Contexts\Context.cs" /> <PackagePath></PackagePath>
<Compile Include="Contexts\ContextAttrib.cs" /> </None>
<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" />
</ItemGroup> </ItemGroup>
<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> </Project>

View File

@@ -1,21 +1,15 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using NSspi.Contexts;
namespace NSspi namespace NSspi
{ {
internal static class NativeMethods internal static class NativeMethods
{ {
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer ); internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo ); internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo );
@@ -23,6 +17,5 @@ namespace NSspi
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )] [DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry ); internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
} }
} }

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {

View File

@@ -1,10 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {
@@ -35,11 +31,11 @@ namespace NSspi
{ {
status = NativeMethods.QuerySecurityPackageInfo( packageName, ref rawInfoPtr ); status = NativeMethods.QuerySecurityPackageInfo( packageName, ref rawInfoPtr );
if ( rawInfoPtr != IntPtr.Zero ) if( rawInfoPtr != IntPtr.Zero )
{ {
try try
{ {
if ( status == SecurityStatus.OK ) if( status == SecurityStatus.OK )
{ {
// This performs allocations as it makes room for the strings contained in the SecPkgInfo class. // This performs allocations as it makes room for the strings contained in the SecPkgInfo class.
Marshal.PtrToStructure( rawInfoPtr, info ); Marshal.PtrToStructure( rawInfoPtr, info );
@@ -71,7 +67,7 @@ namespace NSspi
IntPtr pkgArrayPtr; IntPtr pkgArrayPtr;
IntPtr pkgPtr; IntPtr pkgPtr;
int numPackages = 0; int numPackages = 0;
int pkgSize = Marshal.SizeOf( typeof(SecPkgInfo) ); int pkgSize = Marshal.SizeOf( typeof( SecPkgInfo ) );
pkgArrayPtr = new IntPtr(); pkgArrayPtr = new IntPtr();

View File

@@ -1,36 +1,9 @@
using System.Reflection; using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
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 // 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 // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // 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 // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9abf710c-c646-42aa-8183-76bfa141a07b")] [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.1.0")]
[assembly: AssemblyFileVersion("0.1.1.0")]

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {
@@ -35,7 +31,7 @@ namespace NSspi
protected SSPIException( SerializationInfo info, StreamingContext context ) protected SSPIException( SerializationInfo info, StreamingContext context )
: base( info, context ) : base( info, context )
{ {
this.message = info.GetString( "messsage" ); this.message = info.GetString( "message" );
this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" ); this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" );
} }
@@ -74,7 +70,7 @@ namespace NSspi
"{0}. Error Code = '0x{1:X}' - \"{2}\".", "{0}. Error Code = '0x{1:X}' - \"{2}\".",
this.message, this.message,
this.errorCode, this.errorCode,
EnumMgr.ToText(this.errorCode) EnumMgr.ToText( this.errorCode )
); );
} }
} }

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {
@@ -55,47 +51,47 @@ namespace NSspi
/// <summary> /// <summary>
/// Whether the package supports generating messages with integrity information. Required for MakeSignature and VerifySignature. /// Whether the package supports generating messages with integrity information. Required for MakeSignature and VerifySignature.
/// </summary> /// </summary>
Integrity = 0x1, Integrity = 0x1,
/// <summary> /// <summary>
/// Whether the package supports generating encrypted messages. Required for EncryptMessage and DecryptMessage. /// Whether the package supports generating encrypted messages. Required for EncryptMessage and DecryptMessage.
/// </summary> /// </summary>
Privacy = 0x2, Privacy = 0x2,
/// <summary> /// <summary>
/// Whether the package uses any other buffer information than token buffers. /// Whether the package uses any other buffer information than token buffers.
/// </summary> /// </summary>
TokenOnly = 0x4, TokenOnly = 0x4,
/// <summary> /// <summary>
/// Whether the package supports datagram-style authentication. /// Whether the package supports datagram-style authentication.
/// </summary> /// </summary>
Datagram = 0x8, Datagram = 0x8,
/// <summary> /// <summary>
/// Whether the package supports creating contexts with connection semantics /// Whether the package supports creating contexts with connection semantics
/// </summary> /// </summary>
Connection = 0x10, Connection = 0x10,
/// <summary> /// <summary>
/// Multiple legs are neccessary for authentication. /// Multiple legs are neccessary for authentication.
/// </summary> /// </summary>
MultiLeg = 0x20, MultiLeg = 0x20,
/// <summary> /// <summary>
/// Server authentication is not supported. /// Server authentication is not supported.
/// </summary> /// </summary>
ClientOnly = 0x40, ClientOnly = 0x40,
/// <summary> /// <summary>
/// Supports extended error handling facilities. /// Supports extended error handling facilities.
/// </summary> /// </summary>
ExtendedError = 0x80, ExtendedError = 0x80,
/// <summary> /// <summary>
/// Supports client impersonation on the server. /// Supports client impersonation on the server.
/// </summary> /// </summary>
Impersonation = 0x100, Impersonation = 0x100,
/// <summary> /// <summary>
/// Understands Windows princple and target names. /// Understands Windows princple and target names.
@@ -105,42 +101,42 @@ namespace NSspi
/// <summary> /// <summary>
/// Supports stream semantics /// Supports stream semantics
/// </summary> /// </summary>
Stream = 0x400, Stream = 0x400,
/// <summary> /// <summary>
/// Package may be used by the Negiotiate meta-package. /// Package may be used by the Negiotiate meta-package.
/// </summary> /// </summary>
Negotiable = 0x800, Negotiable = 0x800,
/// <summary> /// <summary>
/// Compatible with GSS. /// Compatible with GSS.
/// </summary> /// </summary>
GssCompatible = 0x1000, GssCompatible = 0x1000,
/// <summary> /// <summary>
/// Supports LsaLogonUser /// Supports LsaLogonUser
/// </summary> /// </summary>
Logon = 0x2000, Logon = 0x2000,
/// <summary> /// <summary>
/// Token buffers are in Ascii format. /// Token buffers are in Ascii format.
/// </summary> /// </summary>
AsciiBuffers = 0x4000, AsciiBuffers = 0x4000,
/// <summary> /// <summary>
/// Supports separating large tokens into multiple buffers. /// Supports separating large tokens into multiple buffers.
/// </summary> /// </summary>
Fragment = 0x8000, Fragment = 0x8000,
/// <summary> /// <summary>
/// Supports mutual authentication between a client and server. /// Supports mutual authentication between a client and server.
/// </summary> /// </summary>
MutualAuth = 0x10000, MutualAuth = 0x10000,
/// <summary> /// <summary>
/// Supports credential delegation from the server to a third context. /// Supports credential delegation from the server to a third context.
/// </summary> /// </summary>
Delegation = 0x20000, Delegation = 0x20000,
/// <summary> /// <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
@@ -157,11 +153,11 @@ namespace NSspi
/// <summary> /// <summary>
/// Extends the negotiate package; only one such package may be registered at any time. /// Extends the negotiate package; only one such package may be registered at any time.
/// </summary> /// </summary>
ExtendsNego = 0x00100000, ExtendsNego = 0x00100000,
/// <summary> /// <summary>
/// This package is negotiated by the package of type ExtendsNego. /// This package is negotiated by the package of type ExtendsNego.
/// </summary> /// </summary>
Negotiable2 = 0x00200000, Negotiable2 = 0x00200000,
} }
} }

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Buffers namespace NSspi.Buffers
{ {

View File

@@ -1,10 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Buffers namespace NSspi.Buffers
{ {
@@ -120,7 +117,7 @@ namespace NSspi.Buffers
this.bufferHandles = new GCHandle[this.buffers.Count]; this.bufferHandles = new GCHandle[this.buffers.Count];
this.bufferCarrier = new SecureBufferInternal[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 ); this.bufferHandles[i] = GCHandle.Alloc( this.buffers[i].Buffer, GCHandleType.Pinned );
@@ -156,7 +153,7 @@ namespace NSspi.Buffers
{ {
get get
{ {
if ( this.disposed ) if( this.disposed )
{ {
throw new ObjectDisposedException( "Cannot use SecureBufferListHandle after it has been disposed" ); throw new ObjectDisposedException( "Cannot use SecureBufferListHandle after it has been disposed" );
} }
@@ -184,9 +181,9 @@ namespace NSspi.Buffers
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
private void Dispose( bool disposing ) 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 and forth to SSPI calls - we need to copy the potentially modified structure members

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Buffers namespace NSspi.Buffers
{ {

View File

@@ -1,10 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Buffers namespace NSspi.Buffers
{ {
@@ -12,7 +7,7 @@ namespace NSspi.Buffers
/// Represents the native layout of the secure buffer descriptor that is provided directly /// Represents the native layout of the secure buffer descriptor that is provided directly
/// to native API calls. /// to native API calls.
/// </summary> /// </summary>
[StructLayout( LayoutKind.Sequential)] [StructLayout( LayoutKind.Sequential )]
internal struct SecureBufferDescInternal internal struct SecureBufferDescInternal
{ {
/// <summary> /// <summary>

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi.Buffers namespace NSspi.Buffers
{ {
@@ -57,7 +53,7 @@ namespace NSspi.Buffers
Stream = 0x0A, Stream = 0x0A,
ChannelBindings = 0x0E, ChannelBindings = 0x0E,
TargetHost = 0x10, TargetHost = 0x10,
ReadOnlyFlag = unchecked( (int)0x80000000 ), ReadOnlyFlag = unchecked((int)0x80000000),
ReadOnlyWithChecksum = 0x10000000 ReadOnlyWithChecksum = 0x10000000
} }
} }

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {
@@ -31,7 +27,7 @@ namespace NSspi
/// The request completed successfully /// The request completed successfully
/// </summary> /// </summary>
[EnumString( "No error" )] [EnumString( "No error" )]
OK = 0x00000000, OK = 0x00000000,
/// <summary> /// <summary>
/// The token returned by the context needs to be provided to the cooperating party /// The token returned by the context needs to be provided to the cooperating party
@@ -45,7 +41,7 @@ namespace NSspi
/// must call CompleteAuthToken. /// must call CompleteAuthToken.
/// </summary> /// </summary>
[EnumString( "Authentication cycle needs to perform a 'complete'." )] [EnumString( "Authentication cycle needs to perform a 'complete'." )]
CompleteNeeded = 0x00090313, CompleteNeeded = 0x00090313,
/// <summary> /// <summary>
/// Occurs after a client calls InitializeSecurityContext to indicate that the client /// 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." )] [EnumString( "The security context was used after its expiration time passed." )]
ContextExpired = 0x00090317, 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." )] [EnumString( "The credentials supplied to the security context were not fully initialized." )]
CredentialsNeeded = 0x00090320, CredentialsNeeded = 0x00090320,
[EnumString( "The context data must be re-negotiated with the peer" )] /// <summary>
Renegotiate = 0x00090321, /// 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 // -------------- Errors --------------
[EnumString( "Not enough memory.")]
OutOfMemory = 0x80090300,
[EnumString( "The handle provided to the API was invalid.")] /// <summary>
InvalidHandle = 0x80090301, /// The SSPI operation failed due to insufficient memory resources.
/// </summary>
[EnumString( "Not enough memory." )]
OutOfMemory = 0x80090300,
[EnumString( "The attempted operation is not supported")] /// <summary>
Unsupported = 0x80090302, /// 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.")] /// <summary>
TargetUnknown = 0x80090303, /// The attempted operation is not supported.
/// </summary>
[EnumString( "The attempted operation is not supported." )]
Unsupported = 0x80090302,
[EnumString( "An internal error occurred" )] /// <summary>
InternalError = 0x80090304, /// 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> /// <summary>
/// No security provider package was found with the given name. /// No security provider package was found with the given name.
/// </summary> /// </summary>
[EnumString( "The requested security package was not found.")] [EnumString( "The requested security package was not found." )]
PackageNotFound = 0x80090305, PackageNotFound = 0x80090305,
NotOwner = 0x80090306, /// <summary>
CannotInstall = 0x80090307, /// 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> /// <summary>
/// A token was provided that contained incorrect or corrupted data. /// A token was provided that contained incorrect or corrupted data.
/// </summary> /// </summary>
[EnumString("The provided authentication token is invalid or corrupted.")] [EnumString( "The provided authentication token is invalid or corrupted." )]
InvalidToken = 0x80090308, InvalidToken = 0x80090308,
CannotPack = 0x80090309, /// <summary>
QopNotSupported = 0x8009030A, /// 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> /// <summary>
/// Impersonation is not supported. /// Impersonation is not supported.
/// </summary> /// </summary>
[EnumString("Impersonation is not supported with the current security package.")] [EnumString( "Impersonation is not supported with the current security package." )]
NoImpersonation = 0x8009030B, NoImpersonation = 0x8009030B,
[EnumString("The logon was denied, perhaps because the provided credentials were incorrect.")] /// <summary>
LogonDenied = 0x8009030C, /// 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.")] /// <summary>
UnknownCredentials = 0x8009030D, /// No credentials are available in the selected security package.
/// </summary>
[EnumString( "No credentials are available in the selected security package.")] [EnumString( "No credentials are available in the selected security package." )]
NoCredentials = 0x8009030E, 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 " + [EnumString( "A message that was provided to the Decrypt or VerifySignature functions was altered " +
"after it was created.")] "after it was created." )]
MessageAltered = 0x8009030F, MessageAltered = 0x8009030F,
[EnumString( "A message was received out of the expected order.")] /// <summary>
OutOfSequence = 0x80090310, /// 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, NoAuthenticatingAuthority = 0x80090311,
/// <summary> /// <summary>
@@ -137,20 +191,88 @@ namespace NSspi
/// will indicate success, but will save off the extra, unrelated data in a buffer of /// will indicate success, but will save off the extra, unrelated data in a buffer of
/// type 'extra'. /// type 'extra'.
/// </remarks> /// </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, IncompleteCredentials = 0x80090320,
BufferNotEnough = 0x80090321,
WrongPrincipal = 0x80090322, /// <summary>
TimeSkew = 0x80090324, /// The buffers supplied to a security function were too small.
UntrustedRoot = 0x80090325, /// </summary>
IllegalMessage = 0x80090326, [EnumString( "The buffers supplied to a security function were too small." )]
CertUnknown = 0x80090327, BufferNotEnough = 0x80090321,
CertExpired = 0x80090328,
AlgorithmMismatch = 0x80090331, /// <summary>
SecurityQosFailed = 0x80090332, /// 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, 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> /// <summary>
@@ -168,5 +290,4 @@ namespace NSspi
return (uint)status > 0x80000000u; return (uint)status > 0x80000000u;
} }
} }
} }

View File

@@ -1,12 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution; using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using NSspi.Contexts;
namespace NSspi namespace NSspi
{ {
@@ -25,7 +19,7 @@ namespace NSspi
/// to this handle for performing work (InitializeSecurityContext, eg) should be performed a CER /// to this handle for performing work (InitializeSecurityContext, eg) should be performed a CER
/// that employs handle reference counting across the native API invocation. /// that employs handle reference counting across the native API invocation.
/// </remarks> /// </remarks>
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ] [StructLayout( LayoutKind.Sequential, Pack = 1 )]
internal struct RawSspiHandle internal struct RawSspiHandle
{ {
private IntPtr lowPart; private IntPtr lowPart;
@@ -46,7 +40,7 @@ namespace NSspi
/// <remarks> /// <remarks>
/// This method is executed in a CER during handle release. /// This method is executed in a CER during handle release.
/// </remarks> /// </remarks>
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
public void SetInvalid() public void SetInvalid()
{ {
this.lowPart = IntPtr.Zero; this.lowPart = IntPtr.Zero;
@@ -61,17 +55,27 @@ namespace NSspi
{ {
internal RawSspiHandle rawHandle; internal RawSspiHandle rawHandle;
/// <summary>
/// Initializes a new instance of the <see cref="SafeSspiHandle"/> class.
/// </summary>
protected SafeSspiHandle() protected SafeSspiHandle()
: base( IntPtr.Zero, true ) : base( IntPtr.Zero, true )
{ {
this.rawHandle = new RawSspiHandle(); this.rawHandle = new RawSspiHandle();
} }
/// <summary>
/// Gets whether the handle is invalid.
/// </summary>
public override bool IsInvalid 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 )] [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {

View File

@@ -1,9 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi namespace NSspi
{ {
@@ -14,6 +10,9 @@ namespace NSspi
[StructLayout( LayoutKind.Sequential )] [StructLayout( LayoutKind.Sequential )]
public struct TimeStamp 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 ); public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
/// <summary> /// <summary>
@@ -29,13 +28,13 @@ namespace NSspi
/// <returns></returns> /// <returns></returns>
public DateTime ToDateTime() public DateTime ToDateTime()
{ {
ulong test = (ulong)this.time + (ulong)(Epoch.Ticks); ulong test = (ulong)this.time + (ulong)( Epoch.Ticks );
// Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value // Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value
// somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999. // somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999.
// It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone // It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone
// http://stackoverflow.com/questions/24478056/ // http://stackoverflow.com/questions/24478056/
if ( test > (ulong)DateTime.MaxValue.Ticks ) if( test > (ulong)DateTime.MaxValue.Ticks )
{ {
return DateTime.MaxValue; return DateTime.MaxValue;
} }

2
NsspiDemo/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bin
obj

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup> </startup>
</configuration> </configuration>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NsspiDemo</RootNamespace> <RootNamespace>NsspiDemo</RootNamespace>
<AssemblyName>NsspiDemo</AssemblyName> <AssemblyName>NsspiDemo</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
@@ -22,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -31,6 +32,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

View File

@@ -16,10 +16,10 @@ namespace NSspi
private static void CredTest( string packageName ) private static void CredTest( string packageName )
{ {
ClientCredential clientCred = null; ClientCurrentCredential clientCred = null;
ClientContext client = null; ClientContext client = null;
ServerCredential serverCred = null; ServerCurrentCredential serverCred = null;
ServerContext server = null; ServerContext server = null;
byte[] clientToken; byte[] clientToken;
@@ -30,8 +30,8 @@ namespace NSspi
try try
{ {
clientCred = new ClientCredential( packageName ); clientCred = new ClientCurrentCredential( packageName );
serverCred = new ServerCredential( packageName ); serverCred = new ServerCurrentCredential( packageName );
Console.Out.WriteLine( clientCred.PrincipleName ); Console.Out.WriteLine( clientCred.PrincipleName );
@@ -47,7 +47,6 @@ namespace NSspi
ContextAttrib.Delegate ContextAttrib.Delegate
); );
server = new ServerContext( server = new ServerContext(
serverCred, serverCred,
ContextAttrib.MutualAuth | ContextAttrib.MutualAuth |
@@ -64,18 +63,17 @@ namespace NSspi
clientStatus = client.Init( serverToken, out clientToken ); clientStatus = client.Init( serverToken, out clientToken );
while ( true ) while( true )
{ {
serverStatus = server.AcceptToken( clientToken, out serverToken ); 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 ); 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 authority: " + server.AuthorityName );
Console.Out.WriteLine( "Server context user: " + server.ContextUserName ); Console.Out.WriteLine( "Server context user: " + server.ContextUserName );
@@ -102,7 +100,7 @@ namespace NSspi
throw new Exception(); 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] )
{ {
@@ -117,25 +115,23 @@ namespace NSspi
throw new Exception(); throw new Exception();
} }
using( server.ImpersonateClient() ) using( server.ImpersonateClient() )
{ {
} }
cipherText = client.MakeSignature( plainText ); cipherText = client.MakeSignature( plainText );
bool goodSig = server.VerifySignature( cipherText, out roundTripPlaintext ); bool goodSig = server.VerifySignature( cipherText, out roundTripPlaintext );
if ( goodSig == false || if( goodSig == false ||
roundTripPlaintext.Length != plainText.Length ) roundTripPlaintext.Length != plainText.Length )
{ {
throw new Exception(); 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(); throw new Exception();
} }
@@ -145,12 +141,12 @@ namespace NSspi
} }
finally finally
{ {
if ( server != null ) if( server != null )
{ {
server.Dispose(); server.Dispose();
} }
if ( client != null ) if( client != null )
{ {
client.Dispose(); client.Dispose();
} }
@@ -160,7 +156,7 @@ namespace NSspi
clientCred.Dispose(); clientCred.Dispose();
} }
if ( serverCred != null ) if( serverCred != null )
{ {
serverCred.Dispose(); serverCred.Dispose();
} }

View File

@@ -1,5 +1,4 @@
using System.Reflection; 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 // General Information about an assembly is controlled through the following

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -19,7 +19,7 @@ namespace NsspiDemo.Properties {
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // 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", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources { internal class Resources {

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -12,7 +12,7 @@ namespace NsspiDemo.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [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", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

2
TestClient/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bin
obj

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup> </startup>
</configuration> </configuration>

View File

@@ -1,12 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using NSspi; using NSspi;
using NSspi.Contexts; using NSspi.Contexts;
@@ -20,7 +14,7 @@ namespace TestClient
public partial class ClientForm : Form public partial class ClientForm : Form
{ {
private ClientContext context; private ClientContext context;
private ClientCredential cred; private ClientCurrentCredential cred;
private CustomConnection connection; private CustomConnection connection;
@@ -48,7 +42,7 @@ namespace TestClient
this.FormClosing += Form1_FormClosing; this.FormClosing += Form1_FormClosing;
// --- SSPI --- // --- SSPI ---
this.cred = new ClientCredential( PackageNames.Negotiate ); this.cred = new ClientCurrentCredential( PackageNames.Negotiate );
this.context = new ClientContext( this.context = new ClientContext(
cred, cred,
@@ -107,7 +101,6 @@ namespace TestClient
throw; throw;
} }
} }
} }
} }
@@ -116,7 +109,6 @@ namespace TestClient
this.connection.Stop(); this.connection.Stop();
} }
private void encryptButton_Click( object sender, EventArgs e ) private void encryptButton_Click( object sender, EventArgs e )
{ {
byte[] plaintext; byte[] plaintext;
@@ -149,7 +141,7 @@ namespace TestClient
private void connection_Received( Message message ) private void connection_Received( Message message )
{ {
this.Invoke( (Action)delegate() this.Invoke( (Action)delegate ()
{ {
if( message.Operation == ProtocolOp.ServerToken ) if( message.Operation == ProtocolOp.ServerToken )
{ {
@@ -180,7 +172,7 @@ namespace TestClient
this.initializing = false; this.initializing = false;
this.lastServerToken = null; this.lastServerToken = null;
this.BeginInvoke( (Action)delegate() this.BeginInvoke( (Action)delegate ()
{ {
this.context.Dispose(); this.context.Dispose();
this.context = new ClientContext( this.context = new ClientContext(
@@ -195,7 +187,7 @@ namespace TestClient
); );
UpdateButtons(); UpdateButtons();
}); } );
} }
private void DoInit() private void DoInit()

View File

@@ -1,18 +1,15 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
namespace TestClient namespace TestClient
{ {
static class Program internal static class Program
{ {
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() private static void Main()
{ {
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false ); Application.SetCompatibleTextRenderingDefault( false );

View File

@@ -1,5 +1,4 @@
using System.Reflection; 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 // General Information about an assembly is controlled through the following

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -19,7 +19,7 @@ namespace TestClient.Properties {
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // 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", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources { internal class Resources {

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -12,7 +12,7 @@ namespace TestClient.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [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", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TestClient</RootNamespace> <RootNamespace>TestClient</RootNamespace>
<AssemblyName>TestClient</AssemblyName> <AssemblyName>TestClient</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
@@ -22,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -31,6 +32,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

2
TestProtocol/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bin
obj

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup> </startup>
</configuration> </configuration>

View File

@@ -1,10 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using NSspi; using NSspi;
@@ -33,7 +29,7 @@ namespace TestProtocol
{ {
if( this.running ) if( this.running )
{ {
throw new InvalidOperationException("Already running"); throw new InvalidOperationException( "Already running" );
} }
this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
@@ -65,7 +61,7 @@ namespace TestProtocol
throw new InvalidOperationException( "Not connected" ); throw new InvalidOperationException( "Not connected" );
} }
byte[] outBuffer = new byte[ message.Data.Length + 8 ]; byte[] outBuffer = new byte[message.Data.Length + 8];
int position = 0; int position = 0;
ByteWriter.WriteInt32_BE( (int)message.Operation, outBuffer, position ); ByteWriter.WriteInt32_BE( (int)message.Operation, outBuffer, position );
@@ -97,10 +93,7 @@ namespace TestProtocol
try try
{ {
if( this.Disconnected != null ) this.Disconnected?.Invoke();
{
this.Disconnected();
}
} }
catch catch
{ } { }
@@ -124,7 +117,6 @@ namespace TestProtocol
// |--4 bytes--|--4 bytes--|---N--| // |--4 bytes--|--4 bytes--|---N--|
// Every command is a TLV - | Operation | Length | Data | // Every command is a TLV - | Operation | Length | Data |
// Read the operation. // Read the operation.
this.socket.Receive( readBuffer, 4, SocketFlags.None ); this.socket.Receive( readBuffer, 4, SocketFlags.None );
@@ -153,7 +145,6 @@ namespace TestProtocol
remaining -= chunkLength; remaining -= chunkLength;
position += chunkLength; position += chunkLength;
} }
} }
catch( SocketException e ) catch( SocketException e )
{ {
@@ -184,10 +175,9 @@ namespace TestProtocol
{ {
this.Received( message ); this.Received( message );
} }
catch( Exception e ) catch( Exception )
{ } { }
} }
} }
} }
} }

View File

@@ -212,7 +212,6 @@ namespace TestProtocol
catch( Exception ) catch( Exception )
{ } { }
} }
} }
try try
@@ -225,5 +224,4 @@ namespace TestProtocol
catch { } catch { }
} }
} }
} }

View File

@@ -1,14 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestProtocol namespace TestProtocol
{ {
public class Message public class Message
{ {
public Message(ProtocolOp op, byte[] data) public Message( ProtocolOp op, byte[] data )
{ {
this.Operation = op; this.Operation = op;
this.Data = data; this.Data = data;

View File

@@ -1,5 +1,4 @@
using System.Reflection; 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 // General Information about an assembly is controlled through the following

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -19,7 +19,7 @@ namespace TestProtocol.Properties {
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // 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", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources { internal class Resources {

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -12,7 +12,7 @@ namespace TestProtocol.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [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", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

View File

@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestProtocol namespace TestProtocol
{ {

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TestProtocol</RootNamespace> <RootNamespace>TestProtocol</RootNamespace>
<AssemblyName>TestProtocol</AssemblyName> <AssemblyName>TestProtocol</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
@@ -22,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -31,6 +32,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<StartupObject /> <StartupObject />

2
TestServer/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
bin
obj

View File

@@ -1,6 +1,6 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup> </startup>
</configuration> </configuration>

View File

@@ -1,18 +1,15 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
namespace TestServer namespace TestServer
{ {
static class Program internal static class Program
{ {
/// <summary> /// <summary>
/// The main entry point for the application. /// The main entry point for the application.
/// </summary> /// </summary>
[STAThread] [STAThread]
static void Main() private static void Main()
{ {
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false ); Application.SetCompatibleTextRenderingDefault( false );

View File

@@ -1,5 +1,4 @@
using System.Reflection; 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 // General Information about an assembly is controlled through the following

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -19,7 +19,7 @@ namespace TestServer.Properties {
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // 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", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources { internal class Resources {

View File

@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@@ -12,7 +12,7 @@ namespace TestServer.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [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", "15.9.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

View File

@@ -1,11 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using TestProtocol; using TestProtocol;
@@ -19,7 +13,7 @@ namespace TestServer
public partial class ServerForm : Form public partial class ServerForm : Form
{ {
private ServerCredential serverCred; private ServerCurrentCredential serverCred;
private ServerContext serverContext; private ServerContext serverContext;
@@ -35,7 +29,7 @@ namespace TestServer
{ {
InitializeComponent(); InitializeComponent();
this.serverCred = new ServerCredential( PackageNames.Negotiate ); this.serverCred = new ServerCurrentCredential( PackageNames.Negotiate );
this.serverContext = new ServerContext( this.serverContext = new ServerContext(
serverCred, serverCred,
@@ -129,7 +123,7 @@ namespace TestServer
{ {
MessageBox.Show( "Starting impersonation: " + Environment.UserName ); MessageBox.Show( "Starting impersonation: " + Environment.UserName );
FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory) + @"\test.txt" ); FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory ) + @"\test.txt" );
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 ); StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
writer.WriteLine( "Hello world." ); writer.WriteLine( "Hello world." );
@@ -150,7 +144,6 @@ namespace TestServer
this.signButton.Enabled = this.connected; this.signButton.Enabled = this.connected;
} }
private void server_Received( Message message ) private void server_Received( Message message )
{ {
if( message.Operation == ProtocolOp.ClientToken ) if( message.Operation == ProtocolOp.ClientToken )
@@ -177,7 +170,6 @@ namespace TestServer
this.initializing = true; this.initializing = true;
this.connected = false; this.connected = false;
this.serverContext.Dispose(); this.serverContext.Dispose();
this.serverContext = new ServerContext( this.serverContext = new ServerContext(
serverCred, serverCred,
@@ -189,14 +181,13 @@ namespace TestServer
ContextAttrib.Confidentiality ContextAttrib.Confidentiality
); );
this.BeginInvoke( (Action)delegate() this.BeginInvoke( (Action)delegate ()
{ {
UpdateButtons(); UpdateButtons();
this.clientUsernameTextBox.Text = ""; this.clientUsernameTextBox.Text = "";
}); } );
} }
private void HandleInit( Message message ) private void HandleInit( Message message )
{ {
byte[] nextToken; byte[] nextToken;
@@ -218,7 +209,7 @@ namespace TestServer
this.initializing = false; this.initializing = false;
this.connected = true; this.connected = true;
this.Invoke( (Action)delegate() this.Invoke( (Action)delegate ()
{ {
UpdateButtons(); UpdateButtons();
this.clientUsernameTextBox.Text = serverContext.ContextUserName; this.clientUsernameTextBox.Text = serverContext.ContextUserName;
@@ -227,18 +218,17 @@ namespace TestServer
} }
else else
{ {
this.Invoke( (Action)delegate() this.Invoke( (Action)delegate ()
{ {
MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status ); MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status );
} ); } );
} }
} }
} }
private void HandleEncrypted( Message message ) private void HandleEncrypted( Message message )
{ {
this.Invoke( (Action)delegate() this.Invoke( (Action)delegate ()
{ {
byte[] plainText = this.serverContext.Decrypt( message.Data ); byte[] plainText = this.serverContext.Decrypt( message.Data );
string text = Encoding.UTF8.GetString( plainText ); string text = Encoding.UTF8.GetString( plainText );
@@ -249,7 +239,7 @@ namespace TestServer
private void HandleSigned( Message message ) private void HandleSigned( Message message )
{ {
this.Invoke( (Action)delegate() this.Invoke( (Action)delegate ()
{ {
byte[] plainText; byte[] plainText;
@@ -268,11 +258,10 @@ namespace TestServer
private void HandleUnknown( Message message ) private void HandleUnknown( Message message )
{ {
this.Invoke( (Action)delegate() this.Invoke( (Action)delegate ()
{ {
MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation ); MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation );
} ); } );
} }
} }
} }

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?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')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>TestServer</RootNamespace> <RootNamespace>TestServer</RootNamespace>
<AssemblyName>TestServer</AssemblyName> <AssemblyName>TestServer</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
@@ -22,6 +22,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -31,6 +32,7 @@
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

View File

@@ -1,5 +1,21 @@
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. ## Downloads ##
The latest release of NSspi is v0.2.1.
Version 0.2.1 is a minor bugfix release that improves impersonation.
* [Source](https://github.com/antiduh/nsspi/archive/0.2.1.zip)
* [Binaries](https://github.com/antiduh/nsspi/releases/download/0.2.1/nsspi-0.2.1-bin.zip)
* [Nuget package](https://www.nuget.org/packages/NSspi)
You can also browse the list of [releases](https://github.com/antiduh/nsspi/releases).
## Introduction ##
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. 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.
The project is provided as a .Net 4.0 assembly, but can just as easily be upgraded to .Net 4.5 or later. The solution file can be opened by Visual Studio 2010 SP1, Visual Studio 2012, or later Visual Studio editions. The project is provided as a .Net 4.0 assembly, but can just as easily be upgraded to .Net 4.5 or later. The solution file can be opened by Visual Studio 2010 SP1, Visual Studio 2012, or later Visual Studio editions.
@@ -8,7 +24,7 @@ The SSPI API provides an interface for real authentication protocols, such as Ke
The SSPI API exposes these packages using a common API, and so a program may invoke one or the other with only minor changes in implementation. SSPI also supports the 'negotiate' 'meta' package, that allows a client and server to decide dynamically which real security provider to use, and then itself provides a passthrough interface to the real package. The SSPI API exposes these packages using a common API, and so a program may invoke one or the other with only minor changes in implementation. SSPI also supports the 'negotiate' 'meta' package, that allows a client and server to decide dynamically which real security provider to use, and then itself provides a passthrough interface to the real package.
==== Usage ==== ## Usage ##
Typically, a client acquires some form of a credential, either from the currently logged on user's security context, by acquiring a username and password from the user, or by some other means. The server acquires a credential in a similar manner. Each uses their credentials to identify themselves to each other. Typically, a client acquires some form of a credential, either from the currently logged on user's security context, by acquiring a username and password from the user, or by some other means. The server acquires a credential in a similar manner. Each uses their credentials to identify themselves to each other.
@@ -26,25 +42,19 @@ The project is broken up into 3 chunks:
may be run on separate machines, that show how one might integrate SSPI into a custom may be run on separate machines, that show how one might integrate SSPI into a custom
application. application.
==== More information ==== ## More information ##
If you would like to understand the SSPI API, feel free to browse the following references: If you would like to understand the SSPI API, feel free to browse the following references:
MSDN documentation on the SSPI API MSDN documentation on the SSPI API:<br/>
http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731(v=vs.85).aspx &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731\(v=vs.85\).aspx)
MSDN article on SSPI along with a sample Managed C++ SSPI library and UI client/servers. MSDN article on SSPI along with a sample Managed C++ SSPI library and UI client/servers.<br/>
http://msdn.microsoft.com/en-us/library/ms973911.aspx &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [http://msdn.microsoft.com/en-us/library/ms973911.aspx](http://msdn.microsoft.com/en-us/library/ms973911.aspx)
Relevant StackOverflow questions: Relevant StackOverflow questions:
"Client-server authentication - using SSPI?"
- http://stackoverflow.com/questions/17241365/
"Validate Windows Identity Token" * [Client-server authentication - using SSPI?](http://stackoverflow.com/questions/17241365/)
- http://stackoverflow.com/questions/11238141/ * [Validate Windows Identity Token](http://stackoverflow.com/questions/11238141/)
* [How to deal with allocations in constrained execution regions?](http://stackoverflow.com/questions/24442209/)
"How to deal with allocations in constrained execution regions?" * [AcquireCredentialsHandle returns massive expiration time](http://stackoverflow.com/questions/24478056/)
- http://stackoverflow.com/questions/24442209/
"AcquireCredentialsHandle returns massive expiration time"
- http://stackoverflow.com/questions/24478056/