From 85288a9dae860de7fdc8f69ae882c2da96f357b6 Mon Sep 17 00:00:00 2001 From: antiduh Date: Fri, 27 Jun 2014 01:29:03 +0000 Subject: [PATCH] Implemented message signature and validation. --- Contexts/Context.cs | 129 +++++++++++++++++++++++++++++++ Contexts/ContextNativeMethods.cs | 18 +++++ Program.cs | 18 +++++ 3 files changed, 165 insertions(+) diff --git a/Contexts/Context.cs b/Contexts/Context.cs index 4d9ca86..0822580 100644 --- a/Contexts/Context.cs +++ b/Contexts/Context.cs @@ -256,6 +256,135 @@ namespace NSspi.Contexts return result; } + public byte[] MakeSignature( byte[] message ) + { + SecurityStatus status = SecurityStatus.InternalError; + + SecPkgContext_Sizes sizes; + SecureBuffer dataBuffer; + SecureBuffer signatureBuffer; + SecureBufferAdapter adapter; + + if ( this.Initialized == false ) + { + throw new InvalidOperationException( "The context is not fully formed" ); + } + + sizes = QueryBufferSizes(); + + dataBuffer = new SecureBuffer( new byte[message.Length], BufferType.Data ); + signatureBuffer = new SecureBuffer( new byte[sizes.MaxSignature], BufferType.Token ); + + Array.Copy( message, dataBuffer.Buffer, message.Length ); + + using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) ) + { + // TODO CER + status = ContextNativeMethods.MakeSignature( + ref this.ContextHandle.rawHandle, + 0, + adapter.Handle, + 0 + ); + } + + if ( status != SecurityStatus.OK ) + { + throw new SSPIException( "Failed to create message signature.", status ); + } + + byte[] outMessage; + int position = 0; + + // Enough room for + // - original message length (4 bytes) + // - signature length (2 bytes) + // - original message + // - signature + + outMessage = new byte[4 + 2 + dataBuffer.Length + signatureBuffer.Length]; + + ByteWriter.WriteInt32_BE( dataBuffer.Length, outMessage, position ); + position += 4; + + ByteWriter.WriteInt16_BE( (Int16)signatureBuffer.Length, outMessage, position ); + position += 2; + + Array.Copy( dataBuffer.Buffer, 0, outMessage, position, dataBuffer.Length ); + position += dataBuffer.Length; + + Array.Copy( signatureBuffer.Buffer, 0, outMessage, position, signatureBuffer.Length ); + position += signatureBuffer.Length; + + return outMessage; + } + + public bool VerifySignature( byte[] signedMessage, out byte[] origMessage ) + { + SecurityStatus status = SecurityStatus.InternalError; + + SecPkgContext_Sizes sizes; + SecureBuffer dataBuffer; + SecureBuffer signatureBuffer; + SecureBufferAdapter adapter; + + if ( this.Initialized == false ) + { + throw new InvalidOperationException( "The context is not fully formed." ); + } + + sizes = QueryBufferSizes(); + + if ( signedMessage.Length < 2 + 4 + sizes.MaxSignature ) + { + throw new ArgumentException( "Input message is too small to possibly fit a valid message" ); + } + + int position = 0; + int messageLen; + int sigLen; + + messageLen = ByteWriter.ReadInt32_BE( signedMessage, 0 ); + position += 4; + + sigLen = ByteWriter.ReadInt16_BE( signedMessage, position ); + position += 2; + + dataBuffer = new SecureBuffer( new byte[messageLen], BufferType.Data ); + Array.Copy( signedMessage, position, dataBuffer.Buffer, 0, messageLen ); + position += messageLen; + + signatureBuffer = new SecureBuffer( new byte[sigLen], BufferType.Token ); + Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen ); + position += sigLen; + + using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) ) + { + status = ContextNativeMethods.VerifySignature( + ref this.ContextHandle.rawHandle, + adapter.Handle, + 0, + 0 + ); + } + + if ( status == SecurityStatus.OK ) + { + origMessage = dataBuffer.Buffer; + return true; + } + else if ( status == SecurityStatus.MessageAltered || + status == SecurityStatus.OutOfSequence ) + { + origMessage = null; + return false; + } + else + { + throw new SSPIException( "Failed to determine the veracity of a signed message.", status ); + } + } + private SecPkgContext_Sizes QueryBufferSizes() { SecPkgContext_Sizes sizes = new SecPkgContext_Sizes(); diff --git a/Contexts/ContextNativeMethods.cs b/Contexts/ContextNativeMethods.cs index 56971f6..57ce8c2 100644 --- a/Contexts/ContextNativeMethods.cs +++ b/Contexts/ContextNativeMethods.cs @@ -126,6 +126,24 @@ namespace NSspi.Contexts int qualityOfProtection ); + [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] + [DllImport( "Secur32.dll", EntryPoint = "MakeSignature", CharSet = CharSet.Unicode )] + internal static extern SecurityStatus MakeSignature( + ref RawSspiHandle contextHandle, + int qualityOfProtection, + IntPtr bufferDescriptor, + int sequenceNumber + ); + + [ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )] + [DllImport( "Secur32.dll", EntryPoint = "VerifySignature", CharSet = CharSet.Unicode )] + internal static extern SecurityStatus VerifySignature( + ref RawSspiHandle contextHandle, + IntPtr bufferDescriptor, + int sequenceNumber, + int qualityOfProtection + ); + [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] [DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )] internal static extern SecurityStatus QueryContextAttributes_Sizes( diff --git a/Program.cs b/Program.cs index 3226955..e84a19f 100644 --- a/Program.cs +++ b/Program.cs @@ -145,6 +145,24 @@ namespace NSspi } + cipherText = client.MakeSignature( plainText ); + + bool goodSig = server.VerifySignature( cipherText, out roundTripPlaintext ); + + if ( goodSig == false || + roundTripPlaintext.Length != plainText.Length ) + { + throw new Exception(); + } + + for ( int i = 0; i < plainText.Length; i++ ) + { + if ( plainText[i] != roundTripPlaintext[i] ) + { + throw new Exception(); + } + } + Console.Out.Flush(); } finally