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 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 ) : 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 credHandle = base.Credential.CredentialHandle;
long prevContextHandle = 0; long prevContextHandle = base.ContextHandle;
long newContextHandle = 0; long newContextHandle = 0;
long expiry = 0; long expiry = 0;
ContextAttrib newContextAttribs = 0;
SecurityStatus status; 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( throw new InvalidOperationException( "Out-of-order usage detected - have a server token, but no previous client token had been created." );
}
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, ref credHandle,
IntPtr.Zero, IntPtr.Zero,
serverPrinc, this.serverPrinc,
attribs, this.requestedAttribs,
0, 0,
SecureBufferDataRep.Network, SecureBufferDataRep.Network,
IntPtr.Zero, IntPtr.Zero,
0, 0,
ref newContextHandle, ref newContextHandle,
list.Handle, outAdapter.Handle,
ref newContextAttribs, ref this.finalAttribs,
ref expiry 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 );
}
Console.Out.WriteLine( "Call status: " + status );
Console.Out.WriteLine( "Buffer length: " + tokenBuffer.Length );
Console.Out.WriteLine( "First bytes: " + tokenBuffer.Buffer[0] );
base.ContextHandle = newContextHandle; 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 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, CharSet = CharSet.Unicode,
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus InitializeSecurityContext_Client1( public static extern SecurityStatus InitializeSecurityContext_1(
ref long credentialHandle, ref long credentialHandle,
IntPtr zero, IntPtr zero,
string serverPrincipleName, string serverPrincipleName,
@@ -187,6 +187,27 @@ namespace NSspi
ref long expiry 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( [DllImport(
"Secur32.dll", "Secur32.dll",