diff --git a/Contexts/ClientContext.cs b/Contexts/ClientContext.cs index 17744ac..c4270c2 100644 --- a/Contexts/ClientContext.cs +++ b/Contexts/ClientContext.cs @@ -50,14 +50,18 @@ namespace NSspi.Contexts } outTokenBuffer = new SecureBuffer( new byte[12288], BufferType.Token ); - serverBuffer = new SecureBuffer( serverToken, BufferType.Token ); + serverBuffer = null; + if ( serverToken != null ) + { + serverBuffer = new SecureBuffer( serverToken, BufferType.Token ); + } using ( outAdapter = new SecureBufferAdapter( outTokenBuffer ) ) { if ( prevContextHandle == 0 ) { - status = NativeMethods.InitializeSecurityContext_1( + status = ContextNativeMethods.InitializeSecurityContext_1( ref credHandle, IntPtr.Zero, this.serverPrinc, @@ -76,7 +80,7 @@ namespace NSspi.Contexts { using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) ) { - status = NativeMethods.InitializeSecurityContext_2( + status = ContextNativeMethods.InitializeSecurityContext_2( ref credHandle, ref prevContextHandle, this.serverPrinc, diff --git a/Contexts/Context.cs b/Contexts/Context.cs index cac0346..89e4aa1 100644 --- a/Contexts/Context.cs +++ b/Contexts/Context.cs @@ -1,4 +1,5 @@ -using System; +using NSspi.Contexts; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -42,7 +43,7 @@ namespace NSspi } long contextHandleCopy = this.ContextHandle; - NativeMethods.DeleteSecurityContext( ref contextHandleCopy ); + ContextNativeMethods.DeleteSecurityContext( ref contextHandleCopy ); this.ContextHandle = 0; diff --git a/Contexts/ContextNativeMethods.cs b/Contexts/ContextNativeMethods.cs index dd57f76..32fb3ed 100644 --- a/Contexts/ContextNativeMethods.cs +++ b/Contexts/ContextNativeMethods.cs @@ -61,5 +61,92 @@ namespace NSspi.Contexts ref ContextAttrib outputAttribs, ref long expiry ); + + // When used in the ClientContext: + /* + SECURITY_STATUS sResult = InitializeSecurityContext( + phCredential, // [in] handle to the credentials + NULL, // [in/out] handle of partially formed context. Always NULL the first time through + pwszServerPrincipalName, // [in] name of the target of the context. Not needed by NTLM + reqContextAttributes, // [in] required context attributes + 0, // [reserved] reserved; must be zero + SECURITY_NATIVE_DREP, // [in] data representation on the target + NULL, // [in/out] pointer to the input buffers. Always NULL the first time through + 0, // [reserved] reserved; must be zero + this->contextHandle, // [in/out] receives the new context handle (must be pre-allocated) + &outBuffDesc, // [out] pointer to the output buffers + pulContextAttributes, // [out] receives the context attributes + &tsLifeSpan // [out] receives the life span of the security context + ); + */ + /* + SECURITY_STATUS SEC_Entry InitializeSecurityContext( + _In_opt_ PCredHandle phCredential, + _In_opt_ PCtxtHandle phContext, + _In_opt_ SEC_CHAR *pszTargetName, + _In_ ULONG fContextReq, + _In_ ULONG Reserved1, + _In_ ULONG TargetDataRep, + _In_opt_ PSecBufferDesc pInput, + _In_ ULONG Reserved2, + _Inout_opt_ PCtxtHandle phNewContext, + _Inout_opt_ PSecBufferDesc pOutput, + _Out_ PULONG pfContextAttr, + _Out_opt_ PTimeStamp ptsExpiry + ); + */ + + [DllImport( + "Secur32.dll", + EntryPoint = "InitializeSecurityContext", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode, + SetLastError = true + )] + public static extern SecurityStatus InitializeSecurityContext_1( + ref long credentialHandle, + IntPtr zero, + string serverPrincipleName, + ContextAttrib requiredAttribs, + int reserved1, + SecureBufferDataRep dataRep, + IntPtr inputBuffer, + int reserved2, + ref long newContextHandle, + IntPtr outputBuffer, + ref ContextAttrib contextAttribs, + ref long expiry + ); + + [DllImport( + "Secur32.dll", + EntryPoint = "InitializeSecurityContext", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode, + SetLastError = true + )] + public static extern SecurityStatus InitializeSecurityContext_2( + ref long credentialHandle, + ref long previousHandle, + string serverPrincipleName, + ContextAttrib requiredAttribs, + int reserved1, + SecureBufferDataRep dataRep, + IntPtr inputBuffer, + int reserved2, + ref long newContextHandle, + IntPtr outputBuffer, + ref ContextAttrib contextAttribs, + ref long expiry + ); + + [DllImport( + "Secur32.dll", + EntryPoint = "DeleteSecurityContext", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode, + SetLastError = true + )] + public static extern SecurityStatus DeleteSecurityContext( ref long contextHandle ); } } diff --git a/Contexts/ServerContext.cs b/Contexts/ServerContext.cs index 5776670..5bec16b 100644 --- a/Contexts/ServerContext.cs +++ b/Contexts/ServerContext.cs @@ -75,6 +75,16 @@ namespace NSspi.Contexts { nextToken = null; this.complete = true; + + if ( outBuffer.Length != 0 ) + { + nextToken = new byte[outBuffer.Length]; + Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length ); + } + else + { + nextToken = null; + } } else if ( status == SecurityStatus.ContinueNeeded ) { diff --git a/NSspi.csproj b/NSspi.csproj index baacf47..b18a9bc 100644 --- a/NSspi.csproj +++ b/NSspi.csproj @@ -48,6 +48,7 @@ + diff --git a/NativeMethods.cs b/NativeMethods.cs index 432a4dd..64b7f4e 100644 --- a/NativeMethods.cs +++ b/NativeMethods.cs @@ -129,93 +129,5 @@ namespace NSspi public IntPtr Name; } - - - // When used in the ClientContext: - /* - SECURITY_STATUS sResult = InitializeSecurityContext( - phCredential, // [in] handle to the credentials - NULL, // [in/out] handle of partially formed context. Always NULL the first time through - pwszServerPrincipalName, // [in] name of the target of the context. Not needed by NTLM - reqContextAttributes, // [in] required context attributes - 0, // [reserved] reserved; must be zero - SECURITY_NATIVE_DREP, // [in] data representation on the target - NULL, // [in/out] pointer to the input buffers. Always NULL the first time through - 0, // [reserved] reserved; must be zero - this->contextHandle, // [in/out] receives the new context handle (must be pre-allocated) - &outBuffDesc, // [out] pointer to the output buffers - pulContextAttributes, // [out] receives the context attributes - &tsLifeSpan // [out] receives the life span of the security context - ); - */ - /* - SECURITY_STATUS SEC_Entry InitializeSecurityContext( - _In_opt_ PCredHandle phCredential, - _In_opt_ PCtxtHandle phContext, - _In_opt_ SEC_CHAR *pszTargetName, - _In_ ULONG fContextReq, - _In_ ULONG Reserved1, - _In_ ULONG TargetDataRep, - _In_opt_ PSecBufferDesc pInput, - _In_ ULONG Reserved2, - _Inout_opt_ PCtxtHandle phNewContext, - _Inout_opt_ PSecBufferDesc pOutput, - _Out_ PULONG pfContextAttr, - _Out_opt_ PTimeStamp ptsExpiry - ); - */ - - [DllImport( - "Secur32.dll", - EntryPoint = "InitializeSecurityContext", - CallingConvention = CallingConvention.Winapi, - CharSet = CharSet.Unicode, - SetLastError = true - )] - public static extern SecurityStatus InitializeSecurityContext_1( - ref long credentialHandle, - IntPtr zero, - string serverPrincipleName, - ContextAttrib requiredAttribs, - int reserved1, - SecureBufferDataRep dataRep, - IntPtr inputBuffer, - int reserved2, - ref long newContextHandle, - IntPtr outputBuffer, - ref ContextAttrib contextAttribs, - ref long expiry - ); - - [DllImport( - "Secur32.dll", - EntryPoint = "InitializeSecurityContext", - CallingConvention = CallingConvention.Winapi, - CharSet = CharSet.Unicode, - SetLastError = true - )] - public static extern SecurityStatus InitializeSecurityContext_2( - ref long credentialHandle, - ref long previousHandle, - string serverPrincipleName, - ContextAttrib requiredAttribs, - int reserved1, - SecureBufferDataRep dataRep, - IntPtr inputBuffer, - int reserved2, - ref long newContextHandle, - IntPtr outputBuffer, - ref ContextAttrib contextAttribs, - ref long expiry - ); - - [DllImport( - "Secur32.dll", - EntryPoint = "DeleteSecurityContext", - CallingConvention = CallingConvention.Winapi, - CharSet = CharSet.Unicode, - SetLastError = true - )] - public static extern SecurityStatus DeleteSecurityContext( ref long contextHandle ); } } diff --git a/Program.cs b/Program.cs index 2327a41..568679d 100644 --- a/Program.cs +++ b/Program.cs @@ -38,15 +38,25 @@ namespace NSspi private static void CredTest() { - ClientCredential cred = null; - ClientContext client; + ClientCredential clientCred = null; + ClientContext client = null; + + ServerCredential serverCred = null; + ServerContext server = null; + + byte[] clientToken; + byte[] serverToken; + + SecurityStatus clientStatus; + SecurityStatus serverStatus; + try { - cred = new ClientCredential( SecurityPackage.Negotiate ); - Console.Out.WriteLine( cred.Name ); + clientCred = new ClientCredential( SecurityPackage.Negotiate ); + Console.Out.WriteLine( clientCred.Name ); client = new ClientContext( - cred, + clientCred, "", ContextAttrib.MutualAuth | ContextAttrib.InitIdentify | @@ -54,14 +64,56 @@ namespace NSspi ContextAttrib.ReplayDetect | ContextAttrib.SequenceDetect ); + + serverCred = new ServerCredential( SecurityPackage.Negotiate ); + + server = new ServerContext( + serverCred, + ContextAttrib.MutualAuth | + ContextAttrib.AcceptIdentify | + ContextAttrib.Confidentiality | + ContextAttrib.ReplayDetect | + ContextAttrib.SequenceDetect + ); + + clientToken = null; + serverToken = null; + + clientStatus = client.Init( serverToken, out clientToken ); + + while ( true ) + { + serverStatus = server.AcceptToken( clientToken, out serverToken ); + + if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; } + + clientStatus = client.Init( serverToken, out clientToken ); + + if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; } + } Console.Out.Flush(); } finally { - if( cred != null ) + if ( server != null ) { - cred.Dispose(); + server.Dispose(); + } + + if ( client != null ) + { + client.Dispose(); + } + + if( clientCred != null ) + { + clientCred.Dispose(); + } + + if ( serverCred != null ) + { + serverCred.Dispose(); } } }