Implemented SafeHandle usage for Context et al. The usage isn't actually safe yet, since I still reference the rawHandle without doing safe (CER) reference counting on the handle.

This commit is contained in:
antiduh
2014-06-24 19:41:19 +00:00
parent a681cc27c5
commit 6b3e395f7c
5 changed files with 72 additions and 49 deletions

View File

@@ -25,9 +25,6 @@ namespace NSspi.Contexts
public SecurityStatus Init( byte[] serverToken, out byte[] outToken ) public SecurityStatus Init( byte[] serverToken, out byte[] outToken )
{ {
long prevContextHandle = base.ContextHandle;
long newContextHandle = 0;
long expiry = 0; long expiry = 0;
SecurityStatus status; SecurityStatus status;
@@ -38,11 +35,11 @@ namespace NSspi.Contexts
SecureBuffer serverBuffer; SecureBuffer serverBuffer;
SecureBufferAdapter serverAdapter; SecureBufferAdapter serverAdapter;
if ( (serverToken != null) && (prevContextHandle == 0) ) if ( (serverToken != null) && ( this.ContextHandle.IsInvalid ) )
{ {
throw new InvalidOperationException( "Out-of-order usage detected - have a server token, but no previous client token had been created." ); 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) ) else if ( (serverToken == null) && ( this.ContextHandle.IsInvalid == false ) )
{ {
throw new InvalidOperationException( "Must provide the server's response when continuing the init process." ); throw new InvalidOperationException( "Must provide the server's response when continuing the init process." );
} }
@@ -55,9 +52,24 @@ namespace NSspi.Contexts
serverBuffer = new SecureBuffer( serverToken, BufferType.Token ); serverBuffer = new SecureBuffer( serverToken, BufferType.Token );
} }
// Some notes on handles and invoking InitializeSecurityContext
// - The first time around, the phContext parameter (the 'old' handle) is a null pointer to what
// would be an RawSspiHandle, to indicate this is the first time it's being called.
// The phNewContext is a pointer (reference) to an RawSspiHandle struct of where to write the
// new handle's values.
// - The next time you invoke ISC, it takes a pointer to the handle it gave you last time in phContext,
// and takes a pointer to where it should write the new handle's values in phNewContext.
// - After the first time, you can provide the same handle to both parameters. From MSDN:
// "On the second call, phNewContext can be the same as the handle specified in the phContext
// parameter."
// It will overwrite the handle you gave it with the new handle value.
// - All handle structures themselves are actually *two* pointer variables, eg, 64 bits on 32-bit
// Windows, 128 bits on 64-bit Windows.
// - So in the end, on a 64-bit machine, we're passing a 64-bit value (the pointer to the struct) that
// points to 128 bits of memory (the struct itself) for where to write the handle numbers.
using ( outAdapter = new SecureBufferAdapter( outTokenBuffer ) ) using ( outAdapter = new SecureBufferAdapter( outTokenBuffer ) )
{ {
if ( prevContextHandle == 0 ) if ( this.ContextHandle.IsInvalid )
{ {
status = ContextNativeMethods.InitializeSecurityContext_1( status = ContextNativeMethods.InitializeSecurityContext_1(
ref this.Credential.Handle.rawHandle, ref this.Credential.Handle.rawHandle,
@@ -68,7 +80,7 @@ namespace NSspi.Contexts
SecureBufferDataRep.Network, SecureBufferDataRep.Network,
IntPtr.Zero, IntPtr.Zero,
0, 0,
ref newContextHandle, ref this.ContextHandle.rawHandle,
outAdapter.Handle, outAdapter.Handle,
ref this.finalAttribs, ref this.finalAttribs,
ref expiry ref expiry
@@ -80,14 +92,14 @@ namespace NSspi.Contexts
{ {
status = ContextNativeMethods.InitializeSecurityContext_2( status = ContextNativeMethods.InitializeSecurityContext_2(
ref this.Credential.Handle.rawHandle, ref this.Credential.Handle.rawHandle,
ref prevContextHandle, ref this.ContextHandle.rawHandle,
this.serverPrinc, this.serverPrinc,
this.requestedAttribs, this.requestedAttribs,
0, 0,
SecureBufferDataRep.Network, SecureBufferDataRep.Network,
serverAdapter.Handle, serverAdapter.Handle,
0, 0,
ref newContextHandle, ref this.ContextHandle.rawHandle,
outAdapter.Handle, outAdapter.Handle,
ref this.finalAttribs, ref this.finalAttribs,
ref expiry ref expiry
@@ -114,8 +126,6 @@ namespace NSspi.Contexts
throw new SSPIException( "Failed to invoke InitializeSecurityContext for a client", status ); throw new SSPIException( "Failed to invoke InitializeSecurityContext for a client", status );
} }
base.ContextHandle = newContextHandle;
return status; return status;
} }
} }

View File

@@ -16,6 +16,8 @@ namespace NSspi
{ {
this.Credential = cred; this.Credential = cred;
this.ContextHandle = new SafeContextHandle();
this.disposed = false; this.disposed = false;
} }
@@ -26,7 +28,7 @@ namespace NSspi
protected Credential Credential { get; private set; } protected Credential Credential { get; private set; }
public long ContextHandle { get; protected set; } public SafeContextHandle ContextHandle { get; protected set; }
public string AuthorityName public string AuthorityName
{ {
@@ -59,10 +61,10 @@ namespace NSspi
this.Credential.Dispose(); this.Credential.Dispose();
} }
long contextHandleCopy = this.ContextHandle; // TODO SAFE_CER
ContextNativeMethods.DeleteSecurityContext( ref contextHandleCopy ); ContextNativeMethods.DeleteSecurityContext( ref this.ContextHandle.rawHandle );
this.ContextHandle = 0; this.ContextHandle.Dispose();
this.disposed = true; this.disposed = true;
} }
@@ -90,8 +92,6 @@ namespace NSspi
SecureBuffer paddingBuffer; SecureBuffer paddingBuffer;
SecureBufferAdapter adapter; SecureBufferAdapter adapter;
long contextHandle = this.ContextHandle;
SecurityStatus status; SecurityStatus status;
byte[] result; byte[] result;
@@ -103,8 +103,9 @@ namespace NSspi
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) ) using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
{ {
// TODO SAFE_CER
status = ContextNativeMethods.EncryptMessage( status = ContextNativeMethods.EncryptMessage(
ref contextHandle, ref this.ContextHandle.rawHandle,
0, 0,
adapter.Handle, adapter.Handle,
0 0
@@ -154,9 +155,7 @@ namespace NSspi
SecureBuffer dataBuffer; SecureBuffer dataBuffer;
SecureBuffer paddingBuffer; SecureBuffer paddingBuffer;
SecureBufferAdapter adapter; SecureBufferAdapter adapter;
long contextHandle = this.ContextHandle;
SecurityStatus status; SecurityStatus status;
byte[] result = null; byte[] result = null;
int remaining; int remaining;
@@ -221,8 +220,9 @@ namespace NSspi
using( adapter = new SecureBufferAdapter( new [] { trailerBuffer, dataBuffer, paddingBuffer } ) ) using( adapter = new SecureBufferAdapter( new [] { trailerBuffer, dataBuffer, paddingBuffer } ) )
{ {
// TODO SAFE_CER
status = ContextNativeMethods.DecryptMessage( status = ContextNativeMethods.DecryptMessage(
ref contextHandle, ref this.ContextHandle.rawHandle,
adapter.Handle, adapter.Handle,
0, 0,
0 0
@@ -243,11 +243,11 @@ namespace NSspi
internal SecPkgContext_Sizes QueryBufferSizes() internal SecPkgContext_Sizes QueryBufferSizes()
{ {
SecPkgContext_Sizes sizes = new SecPkgContext_Sizes(); SecPkgContext_Sizes sizes = new SecPkgContext_Sizes();
long contextHandle = this.ContextHandle;
SecurityStatus status; SecurityStatus status;
// TODO SAFE_CER
status = ContextNativeMethods.QueryContextAttributes_Sizes( status = ContextNativeMethods.QueryContextAttributes_Sizes(
ref contextHandle, ref this.ContextHandle.rawHandle,
ContextQueryAttrib.Sizes, ContextQueryAttrib.Sizes,
ref sizes ref sizes
); );
@@ -263,7 +263,6 @@ namespace NSspi
internal string QueryContextString(ContextQueryAttrib attrib) internal string QueryContextString(ContextQueryAttrib attrib)
{ {
SecPkgContext_String stringAttrib; SecPkgContext_String stringAttrib;
long contextHandle;
SecurityStatus status; SecurityStatus status;
string result; string result;
@@ -274,10 +273,9 @@ namespace NSspi
stringAttrib = new SecPkgContext_String(); stringAttrib = new SecPkgContext_String();
contextHandle = this.ContextHandle; // TODO SAFE_CER
status = ContextNativeMethods.QueryContextAttributes_String( status = ContextNativeMethods.QueryContextAttributes_String(
ref contextHandle, ref this.ContextHandle.rawHandle,
attrib, attrib,
ref stringAttrib ref stringAttrib
); );

View File

@@ -36,7 +36,7 @@ namespace NSspi.Contexts
IntPtr inputBuffer, IntPtr inputBuffer,
ContextAttrib requestedAttribs, ContextAttrib requestedAttribs,
SecureBufferDataRep dataRep, SecureBufferDataRep dataRep,
ref long newContextHandle, ref RawSspiHandle newContextHandle,
IntPtr outputBuffer, IntPtr outputBuffer,
ref ContextAttrib outputAttribs, ref ContextAttrib outputAttribs,
ref long expiry ref long expiry
@@ -52,11 +52,11 @@ namespace NSspi.Contexts
)] )]
public static extern SecurityStatus AcceptSecurityContext_2( public static extern SecurityStatus AcceptSecurityContext_2(
ref RawSspiHandle credHandle, ref RawSspiHandle credHandle,
ref long oldContextHandle, ref RawSspiHandle oldContextHandle,
IntPtr inputBuffer, IntPtr inputBuffer,
ContextAttrib requestedAttribs, ContextAttrib requestedAttribs,
SecureBufferDataRep dataRep, SecureBufferDataRep dataRep,
ref long newContextHandle, ref RawSspiHandle newContextHandle,
IntPtr outputBuffer, IntPtr outputBuffer,
ref ContextAttrib outputAttribs, ref ContextAttrib outputAttribs,
ref long expiry ref long expiry
@@ -112,7 +112,7 @@ namespace NSspi.Contexts
SecureBufferDataRep dataRep, SecureBufferDataRep dataRep,
IntPtr inputBuffer, IntPtr inputBuffer,
int reserved2, int reserved2,
ref long newContextHandle, ref RawSspiHandle newContextHandle,
IntPtr outputBuffer, IntPtr outputBuffer,
ref ContextAttrib contextAttribs, ref ContextAttrib contextAttribs,
ref long expiry ref long expiry
@@ -127,14 +127,14 @@ namespace NSspi.Contexts
)] )]
public static extern SecurityStatus InitializeSecurityContext_2( public static extern SecurityStatus InitializeSecurityContext_2(
ref RawSspiHandle credentialHandle, ref RawSspiHandle credentialHandle,
ref long previousHandle, ref RawSspiHandle previousHandle,
string serverPrincipleName, string serverPrincipleName,
ContextAttrib requiredAttribs, ContextAttrib requiredAttribs,
int reserved1, int reserved1,
SecureBufferDataRep dataRep, SecureBufferDataRep dataRep,
IntPtr inputBuffer, IntPtr inputBuffer,
int reserved2, int reserved2,
ref long newContextHandle, ref RawSspiHandle newContextHandle,
IntPtr outputBuffer, IntPtr outputBuffer,
ref ContextAttrib contextAttribs, ref ContextAttrib contextAttribs,
ref long expiry ref long expiry
@@ -147,7 +147,7 @@ namespace NSspi.Contexts
CharSet = CharSet.Unicode, CharSet = CharSet.Unicode,
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus DeleteSecurityContext( ref long contextHandle ); public static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle );
[DllImport( [DllImport(
"Secur32.dll", "Secur32.dll",
@@ -157,7 +157,7 @@ namespace NSspi.Contexts
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus EncryptMessage( public static extern SecurityStatus EncryptMessage(
ref long contextHandle, ref RawSspiHandle contextHandle,
int qualityOfProtection, int qualityOfProtection,
IntPtr bufferDescriptor, IntPtr bufferDescriptor,
int sequenceNumber int sequenceNumber
@@ -172,7 +172,7 @@ namespace NSspi.Contexts
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus DecryptMessage( public static extern SecurityStatus DecryptMessage(
ref long contextHandle, ref RawSspiHandle contextHandle,
IntPtr bufferDescriptor, IntPtr bufferDescriptor,
int sequenceNumber, int sequenceNumber,
int qualityOfProtection int qualityOfProtection
@@ -184,7 +184,7 @@ namespace NSspi.Contexts
CallingConvention = CallingConvention.Winapi, CallingConvention = CallingConvention.Winapi,
CharSet = CharSet.Unicode )] CharSet = CharSet.Unicode )]
public static extern SecurityStatus QueryContextAttributes_Sizes( public static extern SecurityStatus QueryContextAttributes_Sizes(
ref long contextHandle, ref RawSspiHandle contextHandle,
ContextQueryAttrib attrib, ContextQueryAttrib attrib,
ref SecPkgContext_Sizes sizes ref SecPkgContext_Sizes sizes
); );
@@ -195,7 +195,7 @@ namespace NSspi.Contexts
CallingConvention = CallingConvention.Winapi, CallingConvention = CallingConvention.Winapi,
CharSet = CharSet.Unicode )] CharSet = CharSet.Unicode )]
public static extern SecurityStatus QueryContextAttributes_String( public static extern SecurityStatus QueryContextAttributes_String(
ref long contextHandle, ref RawSspiHandle contextHandle,
ContextQueryAttrib attrib, ContextQueryAttrib attrib,
ref SecPkgContext_String names ref SecPkgContext_String names
); );

View File

@@ -24,21 +24,17 @@ namespace NSspi.Contexts
SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token ); SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
SecureBuffer outBuffer = new SecureBuffer( new byte[12288], BufferType.Token ); SecureBuffer outBuffer = new SecureBuffer( new byte[12288], BufferType.Token );
long oldContextHandle = base.ContextHandle;
long newContextHandle = 0;
SecurityStatus status; SecurityStatus status;
long expiry = 0; long expiry = 0;
SecureBufferAdapter clientAdapter; SecureBufferAdapter clientAdapter;
SecureBufferAdapter outAdapter; SecureBufferAdapter outAdapter;
using ( clientAdapter = new SecureBufferAdapter( clientBuffer ) ) using ( clientAdapter = new SecureBufferAdapter( clientBuffer ) )
{ {
using ( outAdapter = new SecureBufferAdapter( outBuffer ) ) using ( outAdapter = new SecureBufferAdapter( outBuffer ) )
{ {
if ( oldContextHandle == 0 ) if( this.ContextHandle.IsInvalid )
{ {
status = ContextNativeMethods.AcceptSecurityContext_1( status = ContextNativeMethods.AcceptSecurityContext_1(
ref this.Credential.Handle.rawHandle, ref this.Credential.Handle.rawHandle,
@@ -46,7 +42,7 @@ namespace NSspi.Contexts
clientAdapter.Handle, clientAdapter.Handle,
requestedAttribs, requestedAttribs,
SecureBufferDataRep.Network, SecureBufferDataRep.Network,
ref newContextHandle, ref this.ContextHandle.rawHandle,
outAdapter.Handle, outAdapter.Handle,
ref this.finalAttribs, ref this.finalAttribs,
ref expiry ref expiry
@@ -56,15 +52,17 @@ namespace NSspi.Contexts
{ {
status = ContextNativeMethods.AcceptSecurityContext_2( status = ContextNativeMethods.AcceptSecurityContext_2(
ref this.Credential.Handle.rawHandle, ref this.Credential.Handle.rawHandle,
ref oldContextHandle, ref this.ContextHandle.rawHandle,
clientAdapter.Handle, clientAdapter.Handle,
requestedAttribs, requestedAttribs,
SecureBufferDataRep.Network, SecureBufferDataRep.Network,
ref newContextHandle, ref this.ContextHandle.rawHandle,
outAdapter.Handle, outAdapter.Handle,
ref this.finalAttribs, ref this.finalAttribs,
ref expiry ref expiry
); );
} }
} }
} }
@@ -96,8 +94,6 @@ namespace NSspi.Contexts
throw new SSPIException( "Failed to call AcceptSecurityContext", status ); throw new SSPIException( "Failed to call AcceptSecurityContext", status );
} }
base.ContextHandle = newContextHandle;
return status; return status;
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using NSspi.Contexts;
namespace NSspi namespace NSspi
{ {
@@ -83,4 +84,22 @@ namespace NSspi
return status == SecurityStatus.OK; return status == SecurityStatus.OK;
} }
} }
public class SafeContextHandle : SafeSspiHandle
{
public SafeContextHandle()
: base()
{ }
protected override bool ReleaseHandle()
{
SecurityStatus status = ContextNativeMethods.DeleteSecurityContext(
ref base.rawHandle
);
base.ReleaseHandle();
return status == SecurityStatus.OK;
}
}
} }