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:
@@ -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." );
|
||||||
ref credHandle,
|
|
||||||
IntPtr.Zero,
|
|
||||||
serverPrinc,
|
|
||||||
attribs,
|
|
||||||
0,
|
|
||||||
SecureBufferDataRep.Network,
|
|
||||||
IntPtr.Zero,
|
|
||||||
0,
|
|
||||||
ref newContextHandle,
|
|
||||||
list.Handle,
|
|
||||||
ref newContextAttribs,
|
|
||||||
ref expiry
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
else if ( (serverToken == null) && (prevContextHandle != 0) )
|
||||||
Console.Out.WriteLine( "Call status: " + status );
|
{
|
||||||
Console.Out.WriteLine( "Buffer length: " + tokenBuffer.Length );
|
throw new InvalidOperationException( "Must provide the server's response when continuing the init process." );
|
||||||
Console.Out.WriteLine( "First bytes: " + tokenBuffer.Buffer[0] );
|
}
|
||||||
|
|
||||||
|
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;
|
base.ContextHandle = newContextHandle;
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
65
Contexts/ContextNativeMethods.cs
Normal file
65
Contexts/ContextNativeMethods.cs
Normal 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user