From 352e4d18fcd99cf1fa74c8f7c6c4392e37408237 Mon Sep 17 00:00:00 2001 From: antiduh Date: Sun, 22 Jun 2014 16:20:10 +0000 Subject: [PATCH] Working on implementing the ServerContext and structuring things so that invoking the public interface is a little easier - trying to move out of proof-of-concept code to prototype code. Still need to rework how I deal with the context and credential handles, worried that they're not treated safe. Still need to reorganize a lot of where code lives. Very inconsistent so far. --- Contexts/ClientContext.cs | 118 ++++++++++++++++++++++++------- Contexts/ContextNativeMethods.cs | 65 +++++++++++++++++ Contexts/ServerContext.cs | 86 +++++++++++++++++++++- NativeMethods.cs | 23 +++++- 4 files changed, 265 insertions(+), 27 deletions(-) create mode 100644 Contexts/ContextNativeMethods.cs diff --git a/Contexts/ClientContext.cs b/Contexts/ClientContext.cs index 9093f71..17744ac 100644 --- a/Contexts/ClientContext.cs +++ b/Contexts/ClientContext.cs @@ -9,44 +9,112 @@ namespace NSspi.Contexts { public class ClientContext : Context { - public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib attribs ) + private bool complete; + private ContextAttrib requestedAttribs; + private ContextAttrib finalAttribs; + private string serverPrinc; + + public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib requestedAttribs ) : base( cred ) + { + this.complete = false; + + this.serverPrinc = serverPrinc; + this.requestedAttribs = requestedAttribs; + } + + public SecurityStatus Init( byte[] serverToken, out byte[] outToken ) { long credHandle = base.Credential.CredentialHandle; - long prevContextHandle = 0; + long prevContextHandle = base.ContextHandle; long newContextHandle = 0; long expiry = 0; - ContextAttrib newContextAttribs = 0; SecurityStatus status; - SecureBuffer tokenBuffer = new SecureBuffer( new byte[12288], BufferType.Token ); - SecureBufferAdapter list = new SecureBufferAdapter( tokenBuffer ); - using ( list ) + SecureBuffer outTokenBuffer; + SecureBufferAdapter outAdapter; + + SecureBuffer serverBuffer; + SecureBufferAdapter serverAdapter; + + if ( (serverToken != null) && (prevContextHandle == 0) ) { - status = NativeMethods.InitializeSecurityContext_Client1( - ref credHandle, - IntPtr.Zero, - serverPrinc, - attribs, - 0, - SecureBufferDataRep.Network, - IntPtr.Zero, - 0, - ref newContextHandle, - list.Handle, - ref newContextAttribs, - ref expiry - ); + throw new InvalidOperationException( "Out-of-order usage detected - have a server token, but no previous client token had been created." ); } - - Console.Out.WriteLine( "Call status: " + status ); - Console.Out.WriteLine( "Buffer length: " + tokenBuffer.Length ); - Console.Out.WriteLine( "First bytes: " + tokenBuffer.Buffer[0] ); + else if ( (serverToken == null) && (prevContextHandle != 0) ) + { + throw new InvalidOperationException( "Must provide the server's response when continuing the init process." ); + } + + outTokenBuffer = new SecureBuffer( new byte[12288], BufferType.Token ); + serverBuffer = new SecureBuffer( serverToken, BufferType.Token ); + + + using ( outAdapter = new SecureBufferAdapter( outTokenBuffer ) ) + { + if ( prevContextHandle == 0 ) + { + status = NativeMethods.InitializeSecurityContext_1( + ref credHandle, + IntPtr.Zero, + this.serverPrinc, + this.requestedAttribs, + 0, + SecureBufferDataRep.Network, + IntPtr.Zero, + 0, + ref newContextHandle, + outAdapter.Handle, + ref this.finalAttribs, + ref expiry + ); + } + else + { + using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) ) + { + status = NativeMethods.InitializeSecurityContext_2( + ref credHandle, + ref prevContextHandle, + this.serverPrinc, + this.requestedAttribs, + 0, + SecureBufferDataRep.Network, + serverAdapter.Handle, + 0, + ref newContextHandle, + outAdapter.Handle, + ref this.finalAttribs, + ref expiry + ); + } + } + + } + + if ( status == SecurityStatus.OK ) + { + this.complete = true; + outToken = null; + } + else if ( status == SecurityStatus.ContinueNeeded ) + { + this.complete = false; + + outToken = new byte[outTokenBuffer.Length]; + Array.Copy( outTokenBuffer.Buffer, outToken, outToken.Length ); + } + else + { + throw new SSPIException( "Failed to invoke InitializeSecurityContext for a client", status ); + } + base.ContextHandle = newContextHandle; - + + return status; } } } diff --git a/Contexts/ContextNativeMethods.cs b/Contexts/ContextNativeMethods.cs new file mode 100644 index 0000000..dd57f76 --- /dev/null +++ b/Contexts/ContextNativeMethods.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace NSspi.Contexts +{ + public static class ContextNativeMethods + { + /* + SECURITY_STATUS SEC_Entry AcceptSecurityContext( + _In_opt_ PCredHandle phCredential, + _Inout_ PCtxtHandle phContext, + _In_opt_ PSecBufferDesc pInput, + _In_ ULONG fContextReq, + _In_ ULONG TargetDataRep, + _Inout_opt_ PCtxtHandle phNewContext, + _Inout_opt_ PSecBufferDesc pOutput, + _Out_ PULONG pfContextAttr, + _Out_opt_ PTimeStamp ptsTimeStamp + ); + */ + + [DllImport( + "Secur32.dll", + EntryPoint = "AcceptSecurityContext", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode, + SetLastError = true + )] + public static extern SecurityStatus AcceptSecurityContext_1( + ref long credHandle, + IntPtr oldContextHandle, + IntPtr inputBuffer, + ContextAttrib requestedAttribs, + SecureBufferDataRep dataRep, + ref long newContextHandle, + IntPtr outputBuffer, + ref ContextAttrib outputAttribs, + ref long expiry + ); + + + [DllImport( + "Secur32.dll", + EntryPoint = "AcceptSecurityContext", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode, + SetLastError = true + )] + public static extern SecurityStatus AcceptSecurityContext_2( + ref long credHandle, + ref long oldContextHandle, + IntPtr inputBuffer, + ContextAttrib requestedAttribs, + SecureBufferDataRep dataRep, + ref long newContextHandle, + IntPtr outputBuffer, + ref ContextAttrib outputAttribs, + ref long expiry + ); + } +} diff --git a/Contexts/ServerContext.cs b/Contexts/ServerContext.cs index 553b137..5776670 100644 --- a/Contexts/ServerContext.cs +++ b/Contexts/ServerContext.cs @@ -6,7 +6,91 @@ using System.Threading.Tasks; namespace NSspi.Contexts { - class ServerContext + public class ServerContext : Context { + private ContextAttrib requestedAttribs; + private ContextAttrib finalAttribs; + private bool complete; + + public ServerContext(ServerCredential cred, ContextAttrib requestedAttribs) : base ( cred ) + { + this.requestedAttribs = requestedAttribs; + this.finalAttribs = ContextAttrib.Zero; + + } + + public SecurityStatus AcceptToken( byte[] clientToken, out byte[] nextToken ) + { + SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token ); + SecureBuffer outBuffer = new SecureBuffer( new byte[12288], BufferType.Token ); + + long credHandle = this.Credential.CredentialHandle; + long oldContextHandle = base.ContextHandle; + long newContextHandle = 0; + + SecurityStatus status; + ContextAttrib outAttribs = ContextAttrib.Zero; + long expiry = 0; + + SecureBufferAdapter clientAdapter; + SecureBufferAdapter outAdapter; + + + using ( clientAdapter = new SecureBufferAdapter( clientBuffer ) ) + { + using ( outAdapter = new SecureBufferAdapter( outBuffer ) ) + { + if ( oldContextHandle == 0 ) + { + status = ContextNativeMethods.AcceptSecurityContext_1( + ref credHandle, + IntPtr.Zero, + clientAdapter.Handle, + requestedAttribs, + SecureBufferDataRep.Network, + ref newContextHandle, + outAdapter.Handle, + ref outAttribs, + ref expiry + ); + } + else + { + status = ContextNativeMethods.AcceptSecurityContext_2( + ref credHandle, + ref oldContextHandle, + clientAdapter.Handle, + requestedAttribs, + SecureBufferDataRep.Network, + ref newContextHandle, + outAdapter.Handle, + ref outAttribs, + ref expiry + ); + } + } + } + + if ( status == SecurityStatus.OK ) + { + nextToken = null; + this.complete = true; + } + else if ( status == SecurityStatus.ContinueNeeded ) + { + this.complete = false; + + nextToken = new byte[outBuffer.Length]; + Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length ); + } + else + { + throw new SSPIException( "Failed to call AcceptSecurityContext", status ); + } + + base.ContextHandle = newContextHandle; + + return status; + } } } diff --git a/NativeMethods.cs b/NativeMethods.cs index 693108d..432a4dd 100644 --- a/NativeMethods.cs +++ b/NativeMethods.cs @@ -172,7 +172,7 @@ namespace NSspi CharSet = CharSet.Unicode, SetLastError = true )] - public static extern SecurityStatus InitializeSecurityContext_Client1( + public static extern SecurityStatus InitializeSecurityContext_1( ref long credentialHandle, IntPtr zero, string serverPrincipleName, @@ -187,6 +187,27 @@ namespace NSspi 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",