Merge pull request #8 from mcgov/master

Adding QuerySessionKey, as well as QueryContextAttributes and SafeQue…
This commit is contained in:
Kevin Thompson
2017-09-23 15:00:00 -04:00
committed by GitHub
3 changed files with 272 additions and 152 deletions

View File

@@ -28,7 +28,7 @@ namespace NSspi.Contexts
/// and the Initialize method has been called. /// and the Initialize method has been called.
/// </summary> /// </summary>
/// <param name="cred"></param> /// <param name="cred"></param>
protected Context( Credential cred ) protected Context(Credential cred)
{ {
this.Credential = cred; this.Credential = cred;
@@ -61,7 +61,7 @@ namespace NSspi.Contexts
get get
{ {
CheckLifecycle(); CheckLifecycle();
return QueryContextString( ContextQueryAttrib.Authority ); return QueryContextString(ContextQueryAttrib.Authority);
} }
} }
@@ -73,7 +73,7 @@ namespace NSspi.Contexts
get get
{ {
CheckLifecycle(); CheckLifecycle();
return QueryContextString( ContextQueryAttrib.Names ); return QueryContextString(ContextQueryAttrib.Names);
} }
} }
@@ -91,7 +91,7 @@ namespace NSspi.Contexts
/// Marks the context as having completed the initialization process, ie, exchanging of authentication tokens. /// Marks the context as having completed the initialization process, ie, exchanging of authentication tokens.
/// </summary> /// </summary>
/// <param name="expiry">The date and time that the context will expire.</param> /// <param name="expiry">The date and time that the context will expire.</param>
protected void Initialize( DateTime expiry ) protected void Initialize(DateTime expiry)
{ {
this.Expiry = expiry; this.Expiry = expiry;
this.Initialized = true; this.Initialized = true;
@@ -102,19 +102,19 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
Dispose( true ); Dispose(true);
GC.SuppressFinalize( this ); GC.SuppressFinalize(this);
} }
/// <summary> /// <summary>
/// Releases resources associated with the context. /// Releases resources associated with the context.
/// </summary> /// </summary>
/// <param name="disposing">If true, release managed resources, else release only unmanaged resources.</param> /// <param name="disposing">If true, release managed resources, else release only unmanaged resources.</param>
protected virtual void Dispose( bool disposing ) protected virtual void Dispose(bool disposing)
{ {
if( this.Disposed ) { return; } if (this.Disposed) { return; }
if( disposing ) if (disposing)
{ {
this.ContextHandle.Dispose(); this.ContextHandle.Dispose();
} }
@@ -136,7 +136,7 @@ namespace NSspi.Contexts
/// </remarks> /// </remarks>
/// <param name="input">The raw message to encrypt.</param> /// <param name="input">The raw message to encrypt.</param>
/// <returns>The packed and encrypted message.</returns> /// <returns>The packed and encrypted message.</returns>
public byte[] Encrypt( byte[] input ) public byte[] Encrypt(byte[] input)
{ {
// The message is encrypted in place in the buffer we provide to Win32 EncryptMessage // The message is encrypted in place in the buffer we provide to Win32 EncryptMessage
SecPkgContext_Sizes sizes; SecPkgContext_Sizes sizes;
@@ -153,13 +153,13 @@ namespace NSspi.Contexts
sizes = QueryBufferSizes(); sizes = QueryBufferSizes();
trailerBuffer = new SecureBuffer( new byte[sizes.SecurityTrailer], BufferType.Token ); trailerBuffer = new SecureBuffer(new byte[sizes.SecurityTrailer], BufferType.Token);
dataBuffer = new SecureBuffer( new byte[input.Length], BufferType.Data ); dataBuffer = new SecureBuffer(new byte[input.Length], BufferType.Data);
paddingBuffer = new SecureBuffer( new byte[sizes.BlockSize], BufferType.Padding ); paddingBuffer = new SecureBuffer(new byte[sizes.BlockSize], BufferType.Padding);
Array.Copy( input, dataBuffer.Buffer, input.Length ); Array.Copy(input, dataBuffer.Buffer, input.Length);
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) ) using (adapter = new SecureBufferAdapter(new[] { trailerBuffer, dataBuffer, paddingBuffer }))
{ {
status = ContextNativeMethods.SafeEncryptMessage( status = ContextNativeMethods.SafeEncryptMessage(
this.ContextHandle, this.ContextHandle,
@@ -169,9 +169,9 @@ namespace NSspi.Contexts
); );
} }
if( status != SecurityStatus.OK ) if (status != SecurityStatus.OK)
{ {
throw new SSPIException( "Failed to encrypt message", status ); throw new SSPIException("Failed to encrypt message", status);
} }
int position = 0; int position = 0;
@@ -183,22 +183,22 @@ namespace NSspi.Contexts
// -- The encrypted message // -- The encrypted message
result = new byte[2 + 4 + 2 + trailerBuffer.Length + dataBuffer.Length + paddingBuffer.Length]; result = new byte[2 + 4 + 2 + trailerBuffer.Length + dataBuffer.Length + paddingBuffer.Length];
ByteWriter.WriteInt16_BE( (short)trailerBuffer.Length, result, position ); ByteWriter.WriteInt16_BE((short)trailerBuffer.Length, result, position);
position += 2; position += 2;
ByteWriter.WriteInt32_BE( dataBuffer.Length, result, position ); ByteWriter.WriteInt32_BE(dataBuffer.Length, result, position);
position += 4; position += 4;
ByteWriter.WriteInt16_BE( (short)paddingBuffer.Length, result, position ); ByteWriter.WriteInt16_BE((short)paddingBuffer.Length, result, position);
position += 2; position += 2;
Array.Copy( trailerBuffer.Buffer, 0, result, position, trailerBuffer.Length ); Array.Copy(trailerBuffer.Buffer, 0, result, position, trailerBuffer.Length);
position += trailerBuffer.Length; position += trailerBuffer.Length;
Array.Copy( dataBuffer.Buffer, 0, result, position, dataBuffer.Length ); Array.Copy(dataBuffer.Buffer, 0, result, position, dataBuffer.Length);
position += dataBuffer.Length; position += dataBuffer.Length;
Array.Copy( paddingBuffer.Buffer, 0, result, position, paddingBuffer.Length ); Array.Copy(paddingBuffer.Buffer, 0, result, position, paddingBuffer.Length);
position += paddingBuffer.Length; position += paddingBuffer.Length;
return result; return result;
@@ -218,7 +218,7 @@ namespace NSspi.Contexts
/// </remarks> /// </remarks>
/// <param name="input">The packed and encrypted data.</param> /// <param name="input">The packed and encrypted data.</param>
/// <returns>The original plaintext message.</returns> /// <returns>The original plaintext message.</returns>
public byte[] Decrypt( byte[] input ) public byte[] Decrypt(byte[] input)
{ {
SecPkgContext_Sizes sizes; SecPkgContext_Sizes sizes;
@@ -241,63 +241,63 @@ namespace NSspi.Contexts
sizes = QueryBufferSizes(); sizes = QueryBufferSizes();
// This check is required, but not sufficient. We could be stricter. // This check is required, but not sufficient. We could be stricter.
if( input.Length < 2 + 4 + 2 + sizes.SecurityTrailer ) if (input.Length < 2 + 4 + 2 + sizes.SecurityTrailer)
{ {
throw new ArgumentException( "Buffer is too small to possibly contain an encrypted message" ); throw new ArgumentException("Buffer is too small to possibly contain an encrypted message");
} }
position = 0; position = 0;
trailerLength = ByteWriter.ReadInt16_BE( input, position ); trailerLength = ByteWriter.ReadInt16_BE(input, position);
position += 2; position += 2;
dataLength = ByteWriter.ReadInt32_BE( input, position ); dataLength = ByteWriter.ReadInt32_BE(input, position);
position += 4; position += 4;
paddingLength = ByteWriter.ReadInt16_BE( input, position ); paddingLength = ByteWriter.ReadInt16_BE(input, position);
position += 2; position += 2;
if ( trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length ) if (trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length)
{ {
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." ); throw new ArgumentException("The buffer contains invalid data - the embedded length data does not add up.");
} }
trailerBuffer = new SecureBuffer( new byte[trailerLength], BufferType.Token ); trailerBuffer = new SecureBuffer(new byte[trailerLength], BufferType.Token);
dataBuffer = new SecureBuffer( new byte[dataLength], BufferType.Data ); dataBuffer = new SecureBuffer(new byte[dataLength], BufferType.Data);
paddingBuffer = new SecureBuffer( new byte[paddingLength], BufferType.Padding ); paddingBuffer = new SecureBuffer(new byte[paddingLength], BufferType.Padding);
remaining = input.Length - position; remaining = input.Length - position;
if( trailerBuffer.Length <= remaining ) if (trailerBuffer.Length <= remaining)
{ {
Array.Copy( input, position, trailerBuffer.Buffer, 0, trailerBuffer.Length ); Array.Copy(input, position, trailerBuffer.Buffer, 0, trailerBuffer.Length);
position += trailerBuffer.Length; position += trailerBuffer.Length;
remaining -= trailerBuffer.Length; remaining -= trailerBuffer.Length;
} }
else else
{ {
throw new ArgumentException( "Input is missing data - it is not long enough to contain a fully encrypted message" ); throw new ArgumentException("Input is missing data - it is not long enough to contain a fully encrypted message");
} }
if( dataBuffer.Length <= remaining ) if (dataBuffer.Length <= remaining)
{ {
Array.Copy( input, position, dataBuffer.Buffer, 0, dataBuffer.Length ); Array.Copy(input, position, dataBuffer.Buffer, 0, dataBuffer.Length);
position += dataBuffer.Length; position += dataBuffer.Length;
remaining -= dataBuffer.Length; remaining -= dataBuffer.Length;
} }
else else
{ {
throw new ArgumentException( "Input is missing data - it is not long enough to contain a fully encrypted message" ); throw new ArgumentException("Input is missing data - it is not long enough to contain a fully encrypted message");
} }
if( paddingBuffer.Length <= remaining ) if (paddingBuffer.Length <= remaining)
{ {
Array.Copy( input, position, paddingBuffer.Buffer, 0, paddingBuffer.Length ); Array.Copy(input, position, paddingBuffer.Buffer, 0, paddingBuffer.Length);
} }
// else there was no padding. // else there was no padding.
using( adapter = new SecureBufferAdapter( new [] { trailerBuffer, dataBuffer, paddingBuffer } ) ) using (adapter = new SecureBufferAdapter(new[] { trailerBuffer, dataBuffer, paddingBuffer }))
{ {
status = ContextNativeMethods.SafeDecryptMessage( status = ContextNativeMethods.SafeDecryptMessage(
this.ContextHandle, this.ContextHandle,
@@ -307,13 +307,13 @@ namespace NSspi.Contexts
); );
} }
if( status != SecurityStatus.OK ) if (status != SecurityStatus.OK)
{ {
throw new SSPIException( "Failed to encrypt message", status ); throw new SSPIException("Failed to encrypt message", status);
} }
result = new byte[dataBuffer.Length]; result = new byte[dataBuffer.Length];
Array.Copy( dataBuffer.Buffer, 0, result, 0, dataBuffer.Length ); Array.Copy(dataBuffer.Buffer, 0, result, 0, dataBuffer.Length);
return result; return result;
} }
@@ -330,7 +330,7 @@ namespace NSspi.Contexts
/// </remarks> /// </remarks>
/// <param name="message"></param> /// <param name="message"></param>
/// <returns></returns> /// <returns></returns>
public byte[] MakeSignature( byte[] message ) public byte[] MakeSignature(byte[] message)
{ {
SecurityStatus status = SecurityStatus.InternalError; SecurityStatus status = SecurityStatus.InternalError;
@@ -343,12 +343,12 @@ namespace NSspi.Contexts
sizes = QueryBufferSizes(); sizes = QueryBufferSizes();
dataBuffer = new SecureBuffer( new byte[message.Length], BufferType.Data ); dataBuffer = new SecureBuffer(new byte[message.Length], BufferType.Data);
signatureBuffer = new SecureBuffer( new byte[sizes.MaxSignature], BufferType.Token ); signatureBuffer = new SecureBuffer(new byte[sizes.MaxSignature], BufferType.Token);
Array.Copy( message, dataBuffer.Buffer, message.Length ); Array.Copy(message, dataBuffer.Buffer, message.Length);
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) ) using (adapter = new SecureBufferAdapter(new[] { dataBuffer, signatureBuffer }))
{ {
status = ContextNativeMethods.SafeMakeSignature( status = ContextNativeMethods.SafeMakeSignature(
this.ContextHandle, this.ContextHandle,
@@ -358,9 +358,9 @@ namespace NSspi.Contexts
); );
} }
if ( status != SecurityStatus.OK ) if (status != SecurityStatus.OK)
{ {
throw new SSPIException( "Failed to create message signature.", status ); throw new SSPIException("Failed to create message signature.", status);
} }
byte[] outMessage; byte[] outMessage;
@@ -374,21 +374,51 @@ namespace NSspi.Contexts
outMessage = new byte[4 + 2 + dataBuffer.Length + signatureBuffer.Length]; outMessage = new byte[4 + 2 + dataBuffer.Length + signatureBuffer.Length];
ByteWriter.WriteInt32_BE( dataBuffer.Length, outMessage, position ); ByteWriter.WriteInt32_BE(dataBuffer.Length, outMessage, position);
position += 4; position += 4;
ByteWriter.WriteInt16_BE( (Int16)signatureBuffer.Length, outMessage, position ); ByteWriter.WriteInt16_BE((Int16)signatureBuffer.Length, outMessage, position);
position += 2; position += 2;
Array.Copy( dataBuffer.Buffer, 0, outMessage, position, dataBuffer.Length ); Array.Copy(dataBuffer.Buffer, 0, outMessage, position, dataBuffer.Length);
position += dataBuffer.Length; position += dataBuffer.Length;
Array.Copy( signatureBuffer.Buffer, 0, outMessage, position, signatureBuffer.Length ); Array.Copy(signatureBuffer.Buffer, 0, outMessage, position, signatureBuffer.Length);
position += signatureBuffer.Length; position += signatureBuffer.Length;
return outMessage; return outMessage;
} }
/// <summary>
/// Returns the Session Key from a context or null on failure.
/// </summary>
/// <remarks>
/// Session keys are sometimes needed for other purposes or HMAC functions. This function will run QueryAttribute to get the session key struct, and read and return the key from that struct.
/// </remarks>
///
/// <returns>byte[] with the session key data or null on failure</returns>
public byte[] QuerySessionKey()
{
SecurityStatus status = SecurityStatus.InternalError;
byte[] SessionKey = null;
status = ContextNativeMethods.SafeQueryContextAttribute(
this.ContextHandle,
ContextQueryAttrib.SessionKey,
ref SessionKey
);
if (status != SecurityStatus.OK)
{
throw new SSPIException("Failed to query session key.", status);
}
return SessionKey;
}
/// <summary> /// <summary>
/// Verifies the signature of a signed message /// Verifies the signature of a signed message
/// </summary> /// </summary>
@@ -402,7 +432,7 @@ namespace NSspi.Contexts
/// <param name="signedMessage">The packed signed message.</param> /// <param name="signedMessage">The packed signed message.</param>
/// <param name="origMessage">The extracted original message.</param> /// <param name="origMessage">The extracted original message.</param>
/// <returns>True if the message has a valid signature, false otherwise.</returns> /// <returns>True if the message has a valid signature, false otherwise.</returns>
public bool VerifySignature( byte[] signedMessage, out byte[] origMessage ) public bool VerifySignature(byte[] signedMessage, out byte[] origMessage)
{ {
SecurityStatus status = SecurityStatus.InternalError; SecurityStatus status = SecurityStatus.InternalError;
@@ -415,35 +445,35 @@ namespace NSspi.Contexts
sizes = QueryBufferSizes(); sizes = QueryBufferSizes();
if ( signedMessage.Length < 2 + 4 + sizes.MaxSignature ) if (signedMessage.Length < 2 + 4 + sizes.MaxSignature)
{ {
throw new ArgumentException( "Input message is too small to possibly fit a valid message" ); throw new ArgumentException("Input message is too small to possibly fit a valid message");
} }
int position = 0; int position = 0;
int messageLen; int messageLen;
int sigLen; int sigLen;
messageLen = ByteWriter.ReadInt32_BE( signedMessage, 0 ); messageLen = ByteWriter.ReadInt32_BE(signedMessage, 0);
position += 4; position += 4;
sigLen = ByteWriter.ReadInt16_BE( signedMessage, position ); sigLen = ByteWriter.ReadInt16_BE(signedMessage, position);
position += 2; position += 2;
if ( messageLen + sigLen + 2 + 4 > signedMessage.Length ) if (messageLen + sigLen + 2 + 4 > signedMessage.Length)
{ {
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." ); throw new ArgumentException("The buffer contains invalid data - the embedded length data does not add up.");
} }
dataBuffer = new SecureBuffer( new byte[messageLen], BufferType.Data ); dataBuffer = new SecureBuffer(new byte[messageLen], BufferType.Data);
Array.Copy( signedMessage, position, dataBuffer.Buffer, 0, messageLen ); Array.Copy(signedMessage, position, dataBuffer.Buffer, 0, messageLen);
position += messageLen; position += messageLen;
signatureBuffer = new SecureBuffer( new byte[sigLen], BufferType.Token ); signatureBuffer = new SecureBuffer(new byte[sigLen], BufferType.Token);
Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen ); Array.Copy(signedMessage, position, signatureBuffer.Buffer, 0, sigLen);
position += sigLen; position += sigLen;
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) ) using (adapter = new SecureBufferAdapter(new[] { dataBuffer, signatureBuffer }))
{ {
status = ContextNativeMethods.SafeVerifySignature( status = ContextNativeMethods.SafeVerifySignature(
this.ContextHandle, this.ContextHandle,
@@ -453,20 +483,20 @@ namespace NSspi.Contexts
); );
} }
if ( status == SecurityStatus.OK ) if (status == SecurityStatus.OK)
{ {
origMessage = dataBuffer.Buffer; origMessage = dataBuffer.Buffer;
return true; return true;
} }
else if ( status == SecurityStatus.MessageAltered || else if (status == SecurityStatus.MessageAltered ||
status == SecurityStatus.OutOfSequence ) status == SecurityStatus.OutOfSequence)
{ {
origMessage = null; origMessage = null;
return false; return false;
} }
else else
{ {
throw new SSPIException( "Failed to determine the veracity of a signed message.", status ); throw new SSPIException("Failed to determine the veracity of a signed message.", status);
} }
} }
@@ -483,11 +513,11 @@ namespace NSspi.Contexts
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
this.ContextHandle.DangerousAddRef( ref gotRef ); this.ContextHandle.DangerousAddRef(ref gotRef);
} }
catch ( Exception ) catch (Exception)
{ {
if ( gotRef ) if (gotRef)
{ {
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -497,7 +527,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if (gotRef)
{ {
status = ContextNativeMethods.QueryContextAttributes_Sizes( status = ContextNativeMethods.QueryContextAttributes_Sizes(
ref this.ContextHandle.rawHandle, ref this.ContextHandle.rawHandle,
@@ -508,9 +538,9 @@ namespace NSspi.Contexts
} }
} }
if( status != SecurityStatus.OK ) if (status != SecurityStatus.OK)
{ {
throw new SSPIException( "Failed to query context buffer size attributes", status ); throw new SSPIException("Failed to query context buffer size attributes", status);
} }
return sizes; return sizes;
@@ -528,9 +558,9 @@ namespace NSspi.Contexts
string result = null; string result = null;
bool gotRef = false; bool gotRef = false;
if( attrib != ContextQueryAttrib.Names && attrib != ContextQueryAttrib.Authority ) if (attrib != ContextQueryAttrib.Names && attrib != ContextQueryAttrib.Authority)
{ {
throw new InvalidOperationException( "QueryContextString can only be used to query context Name and Authority attributes" ); throw new InvalidOperationException("QueryContextString can only be used to query context Name and Authority attributes");
} }
stringAttrib = new SecPkgContext_String(); stringAttrib = new SecPkgContext_String();
@@ -538,11 +568,11 @@ namespace NSspi.Contexts
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
this.ContextHandle.DangerousAddRef( ref gotRef ); this.ContextHandle.DangerousAddRef(ref gotRef);
} }
catch ( Exception ) catch (Exception)
{ {
if ( gotRef ) if (gotRef)
{ {
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -551,7 +581,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if (gotRef)
{ {
status = ContextNativeMethods.QueryContextAttributes_String( status = ContextNativeMethods.QueryContextAttributes_String(
ref this.ContextHandle.rawHandle, ref this.ContextHandle.rawHandle,
@@ -561,21 +591,21 @@ namespace NSspi.Contexts
this.ContextHandle.DangerousRelease(); this.ContextHandle.DangerousRelease();
if ( status == SecurityStatus.OK ) if (status == SecurityStatus.OK)
{ {
result = Marshal.PtrToStringUni( stringAttrib.StringResult ); result = Marshal.PtrToStringUni(stringAttrib.StringResult);
ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult ); ContextNativeMethods.FreeContextBuffer(stringAttrib.StringResult);
} }
} }
} }
if( status == SecurityStatus.Unsupported ) if (status == SecurityStatus.Unsupported)
{ {
return null; return null;
} }
else if( status != SecurityStatus.OK ) else if (status != SecurityStatus.OK)
{ {
throw new SSPIException( "Failed to query the context's associated user name", status ); throw new SSPIException("Failed to query the context's associated user name", status);
} }
return result; return result;
@@ -587,13 +617,13 @@ namespace NSspi.Contexts
/// </summary> /// </summary>
private void CheckLifecycle() private void CheckLifecycle()
{ {
if( this.Initialized == false ) if (this.Initialized == false)
{ {
throw new InvalidOperationException( "The context is not yet fully formed." ); throw new InvalidOperationException("The context is not yet fully formed.");
} }
else if( this.Disposed ) else if (this.Disposed)
{ {
throw new ObjectDisposedException( "Context" ); throw new ObjectDisposedException("Context");
} }
} }
} }

View File

@@ -45,7 +45,7 @@ namespace NSspi.Contexts
); );
*/ */
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext",CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus AcceptSecurityContext_1( internal static extern SecurityStatus AcceptSecurityContext_1(
ref RawSspiHandle credHandle, ref RawSspiHandle credHandle,
IntPtr oldContextHandle, IntPtr oldContextHandle,
@@ -59,7 +59,7 @@ namespace NSspi.Contexts
); );
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus AcceptSecurityContext_2( internal static extern SecurityStatus AcceptSecurityContext_2(
ref RawSspiHandle credHandle, ref RawSspiHandle credHandle,
ref RawSspiHandle oldContextHandle, ref RawSspiHandle oldContextHandle,
@@ -73,7 +73,7 @@ namespace NSspi.Contexts
); );
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus InitializeSecurityContext_1( internal static extern SecurityStatus InitializeSecurityContext_1(
ref RawSspiHandle credentialHandle, ref RawSspiHandle credentialHandle,
IntPtr zero, IntPtr zero,
@@ -90,7 +90,7 @@ namespace NSspi.Contexts
); );
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus InitializeSecurityContext_2( internal static extern SecurityStatus InitializeSecurityContext_2(
ref RawSspiHandle credentialHandle, ref RawSspiHandle credentialHandle,
ref RawSspiHandle previousHandle, ref RawSspiHandle previousHandle,
@@ -106,13 +106,13 @@ namespace NSspi.Contexts
ref TimeStamp expiry ref TimeStamp expiry
); );
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle ); internal static extern SecurityStatus DeleteSecurityContext(ref RawSspiHandle contextHandle);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus EncryptMessage( internal static extern SecurityStatus EncryptMessage(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
int qualityOfProtection, int qualityOfProtection,
@@ -120,8 +120,8 @@ namespace NSspi.Contexts
int sequenceNumber int sequenceNumber
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport( "Secur32.dll", EntryPoint = "DecryptMessage", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "DecryptMessage", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus DecryptMessage( internal static extern SecurityStatus DecryptMessage(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
IntPtr bufferDescriptor, IntPtr bufferDescriptor,
@@ -129,8 +129,8 @@ namespace NSspi.Contexts
int qualityOfProtection int qualityOfProtection
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport( "Secur32.dll", EntryPoint = "MakeSignature", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "MakeSignature", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus MakeSignature( internal static extern SecurityStatus MakeSignature(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
int qualityOfProtection, int qualityOfProtection,
@@ -138,8 +138,8 @@ namespace NSspi.Contexts
int sequenceNumber int sequenceNumber
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport( "Secur32.dll", EntryPoint = "VerifySignature", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "VerifySignature", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus VerifySignature( internal static extern SecurityStatus VerifySignature(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
IntPtr bufferDescriptor, IntPtr bufferDescriptor,
@@ -147,34 +147,111 @@ namespace NSspi.Contexts
int qualityOfProtection int qualityOfProtection
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus QueryContextAttributes_Sizes( internal static extern SecurityStatus QueryContextAttributes_Sizes(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
ContextQueryAttrib attrib, ContextQueryAttrib attrib,
ref SecPkgContext_Sizes sizes ref SecPkgContext_Sizes sizes
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus QueryContextAttributes_String( internal static extern SecurityStatus QueryContextAttributes_String(
ref RawSspiHandle contextHandle, ref RawSspiHandle contextHandle,
ContextQueryAttrib attrib, ContextQueryAttrib attrib,
ref SecPkgContext_String names ref SecPkgContext_String names
); );
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle ); internal static extern SecurityStatus QueryContextAttributes(
ref RawSspiHandle contextHandle,
ContextQueryAttrib attrib,
IntPtr attribute
);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport("Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus FreeContextBuffer(IntPtr handle);
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )] [DllImport("Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle ); internal static extern SecurityStatus ImpersonateSecurityContext(ref RawSspiHandle contextHandle);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport("Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode)]
internal static extern SecurityStatus RevertSecurityContext(ref RawSspiHandle contextHandle);
[StructLayout(LayoutKind.Sequential)]
class KeyStruct
{
public int size;
public IntPtr data;
}
internal static SecurityStatus SafeQueryContextAttribute(
SafeContextHandle handle,
ContextQueryAttrib attribute,
ref byte[] buffer
)
{
bool gotRef = false;
SecurityStatus status = SecurityStatus.InternalError;
RuntimeHelpers.PrepareConstrainedRegions();
int pointerSize = System.Environment.Is64BitOperatingSystem ? 8 : 4; //NOTE: update this when 128 bit processors exist
IntPtr alloc_buffer = Marshal.AllocHGlobal(sizeof(uint) + pointerSize); //NOTE: this is at most 4 + sizeof(void*) bytes
//see struct SecPkgContext_SessionKey
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380096(v=vs.85).aspx
try
{
handle.DangerousAddRef(ref gotRef);
}
catch (Exception)
{
if (gotRef)
{
handle.DangerousRelease();
gotRef = false;
buffer = null;
}
throw;
}
finally
{
if (gotRef)
{
status = ContextNativeMethods.QueryContextAttributes(
ref handle.rawHandle,
attribute,
alloc_buffer
);
if (status == SecurityStatus.OK)
{
KeyStruct key = new KeyStruct();
Marshal.PtrToStructure(alloc_buffer, key); // fit to the proper size, read a byte[]
byte[] sizedBuffer = new byte[key.size];
for (int i = 0; i < key.size; i++)
sizedBuffer[i] = Marshal.ReadByte(key.data, i);
buffer = sizedBuffer;
}
handle.DangerousRelease();
}
}
Marshal.FreeHGlobal(alloc_buffer);
return status;
}
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
/// <summary> /// <summary>
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is /// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
@@ -189,7 +266,7 @@ namespace NSspi.Contexts
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
SecureBufferAdapter bufferAdapter, SecureBufferAdapter bufferAdapter,
int sequenceNumber ) int sequenceNumber)
{ {
SecurityStatus status = SecurityStatus.InternalError; SecurityStatus status = SecurityStatus.InternalError;
bool gotRef = false; bool gotRef = false;
@@ -197,11 +274,11 @@ namespace NSspi.Contexts
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef(ref gotRef);
} }
catch ( Exception ) catch (Exception)
{ {
if ( gotRef ) if (gotRef)
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -211,7 +288,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if (gotRef)
{ {
status = ContextNativeMethods.EncryptMessage( status = ContextNativeMethods.EncryptMessage(
ref handle.rawHandle, ref handle.rawHandle,
@@ -240,7 +317,7 @@ namespace NSspi.Contexts
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
SecureBufferAdapter bufferAdapter, SecureBufferAdapter bufferAdapter,
int sequenceNumber ) int sequenceNumber)
{ {
SecurityStatus status = SecurityStatus.InvalidHandle; SecurityStatus status = SecurityStatus.InvalidHandle;
bool gotRef = false; bool gotRef = false;
@@ -248,11 +325,11 @@ namespace NSspi.Contexts
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef(ref gotRef);
} }
catch( Exception ) catch (Exception)
{ {
if( gotRef ) if (gotRef)
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -262,7 +339,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if( gotRef ) if (gotRef)
{ {
status = ContextNativeMethods.DecryptMessage( status = ContextNativeMethods.DecryptMessage(
ref handle.rawHandle, ref handle.rawHandle,
@@ -291,7 +368,7 @@ namespace NSspi.Contexts
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
SecureBufferAdapter adapter, SecureBufferAdapter adapter,
int sequenceNumber ) int sequenceNumber)
{ {
bool gotRef = false; bool gotRef = false;
SecurityStatus status = SecurityStatus.InternalError; SecurityStatus status = SecurityStatus.InternalError;
@@ -299,11 +376,11 @@ namespace NSspi.Contexts
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef(ref gotRef);
} }
catch ( Exception ) catch (Exception)
{ {
if ( gotRef ) if (gotRef)
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -313,7 +390,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if (gotRef)
{ {
status = ContextNativeMethods.MakeSignature( status = ContextNativeMethods.MakeSignature(
ref handle.rawHandle, ref handle.rawHandle,
@@ -342,7 +419,7 @@ namespace NSspi.Contexts
SafeContextHandle handle, SafeContextHandle handle,
int qualityOfProtection, int qualityOfProtection,
SecureBufferAdapter adapter, SecureBufferAdapter adapter,
int sequenceNumber ) int sequenceNumber)
{ {
bool gotRef = false; bool gotRef = false;
SecurityStatus status = SecurityStatus.InternalError; SecurityStatus status = SecurityStatus.InternalError;
@@ -350,11 +427,11 @@ namespace NSspi.Contexts
RuntimeHelpers.PrepareConstrainedRegions(); RuntimeHelpers.PrepareConstrainedRegions();
try try
{ {
handle.DangerousAddRef( ref gotRef ); handle.DangerousAddRef(ref gotRef);
} }
catch ( Exception ) catch (Exception)
{ {
if ( gotRef ) if (gotRef)
{ {
handle.DangerousRelease(); handle.DangerousRelease();
gotRef = false; gotRef = false;
@@ -364,7 +441,7 @@ namespace NSspi.Contexts
} }
finally finally
{ {
if ( gotRef ) if (gotRef)
{ {
status = ContextNativeMethods.VerifySignature( status = ContextNativeMethods.VerifySignature(
ref handle.rawHandle, ref handle.rawHandle,

View File

@@ -36,5 +36,18 @@ namespace NSspi.Contexts
/// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure. /// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
/// </remarks> /// </remarks>
Authority = 6, Authority = 6,
/// <summary>
/// Queries the context for it's neogtiated SessionKey
/// </summary>
/// <remarks>
/// Results for a query of this type are stored in a Win32 SecPkgContext_SessionKey structure
/// </remarks>
SessionKey = 9,
AccessToken = 13, //not implemented yet but this would be cool
} }
} }