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.

This commit is contained in:
antiduh
2014-06-22 16:20:10 +00:00
parent a079449f85
commit 352e4d18fc
4 changed files with 265 additions and 27 deletions

View File

@@ -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;
}
}
}

View File

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

View File

@@ -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;
}
}
}

View File

@@ -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",