diff --git a/Contexts/Context.cs b/Contexts/Context.cs index f5e5cd3..cd9d922 100644 --- a/Contexts/Context.cs +++ b/Contexts/Context.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Runtime.InteropServices; namespace NSspi { @@ -27,6 +28,22 @@ namespace NSspi public long ContextHandle { get; protected set; } + public string AuthorityName + { + get + { + return QueryContextString( ContextQueryAttrib.Authority ); + } + } + + public string ContextUserName + { + get + { + return QueryContextString( ContextQueryAttrib.Names ); + } + } + public void Dispose() { Dispose( true ); @@ -50,8 +67,79 @@ namespace NSspi this.disposed = true; } + /// + /// Encrypts the byte array using the context's session key. The encrypted data is stored in a new + /// byte array, which is formatted such that the first four bytes are the original message length + /// as an unsigned integer and the remaining bytes are the encrypted bytes of the original message. + /// + /// + /// public byte[] Encrypt( byte[] input ) { + // The message is encrypted in place in the buffer we provide to Win32 EncryptMessage + return null; } + + internal SecPkgContext_Sizes QueryBufferSizes() + { + SecPkgContext_Sizes sizes = new SecPkgContext_Sizes(); + long contextHandle = this.ContextHandle; + SecurityStatus status; + + status = ContextNativeMethods.QueryContextAttributes_Sizes( + ref contextHandle, + ContextQueryAttrib.Sizes, + ref sizes + ); + + if( status != SecurityStatus.OK ) + { + throw new SSPIException( "Failed to query context buffer size attributes", status ); + } + + return sizes; + } + + internal string QueryContextString(ContextQueryAttrib attrib) + { + SecPkgContext_String stringAttrib; + long contextHandle; + SecurityStatus status; + string result; + + if( attrib != ContextQueryAttrib.Names && attrib != ContextQueryAttrib.Authority ) + { + throw new InvalidOperationException( "QueryContextString can only be used to query context Name and Authority attributes" ); + } + + stringAttrib = new SecPkgContext_String(); + + contextHandle = this.ContextHandle; + + status = ContextNativeMethods.QueryContextAttributes_String( + ref contextHandle, + attrib, + ref stringAttrib + ); + + + if( status == SecurityStatus.Unsupported ) + { + return null; + } + else if( status == SecurityStatus.OK ) + { + // TODO handle this safely. + result = Marshal.PtrToStringUni( stringAttrib.StringResult ); + ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult ); + } + else + { + throw new SSPIException( "Failed to query the context's associated user name", status ); + } + + return result; + } + } } diff --git a/Contexts/ContextNativeMethods.cs b/Contexts/ContextNativeMethods.cs index 913f53b..7e1893d 100644 --- a/Contexts/ContextNativeMethods.cs +++ b/Contexts/ContextNativeMethods.cs @@ -151,7 +151,7 @@ namespace NSspi.Contexts [DllImport( "Secur32.dll", - EntryPoint = "EncryptMessag", + EntryPoint = "EncryptMessage", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true @@ -162,5 +162,35 @@ namespace NSspi.Contexts IntPtr bufferDescriptor, int sequenceNumber ); + + [DllImport( + "Secur32.dll", + EntryPoint = "QueryContextAttributes", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode )] + public static extern SecurityStatus QueryContextAttributes_Sizes( + ref long contextHandle, + ContextQueryAttrib attrib, + ref SecPkgContext_Sizes sizes + ); + + [DllImport( + "Secur32.dll", + EntryPoint = "QueryContextAttributes", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode )] + public static extern SecurityStatus QueryContextAttributes_String( + ref long contextHandle, + ContextQueryAttrib attrib, + ref SecPkgContext_String names + ); + + + [DllImport( + "Secur32.dll", + EntryPoint = "FreeContextBuffer", + CallingConvention = CallingConvention.Winapi, + CharSet = CharSet.Unicode )] + public static extern SecurityStatus FreeContextBuffer( IntPtr handle ); } } diff --git a/Contexts/ContextQueries.cs b/Contexts/ContextQueries.cs new file mode 100644 index 0000000..7df6785 --- /dev/null +++ b/Contexts/ContextQueries.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace NSspi.Contexts +{ + + [StructLayout( LayoutKind.Sequential )] + public struct SecPkgContext_Sizes + { + public int MaxToken; + public int MaxSignature; + public int BlockSize; + public int SecurityTrailer; + } + + [StructLayout( LayoutKind.Sequential )] + public struct SecPkgContext_String + { + public IntPtr StringResult; + } + + + public class ContextQueryHandle : SafeHandle + { + public ContextQueryHandle() : + base( IntPtr.Zero, true ) + { + } + + public override bool IsInvalid + { + get { return base.handle.Equals( IntPtr.Zero ); } + } + + protected override bool ReleaseHandle() + { + return ContextNativeMethods.FreeContextBuffer( base.handle ) == SecurityStatus.OK; + } + } +} diff --git a/Contexts/ContextQueryAttrib.cs b/Contexts/ContextQueryAttrib.cs new file mode 100644 index 0000000..a3019e1 --- /dev/null +++ b/Contexts/ContextQueryAttrib.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NSspi.Contexts +{ + /// + /// Defines the types of queries that can be performed with QueryContextAttribute. + /// Each query has a different result buffer. + /// + public enum ContextQueryAttrib : int + { + /// + /// Queries the buffer size parameters when performing message functions, such + /// as encryption, decryption, signing and signature validation. + /// + /// + /// Results for a query of this type are stored in a Win32 SecPkgContext_Sizes structure. + /// + Sizes = 0, + + /// + /// Queries the context for the name of the user assocated with a security context. + /// + /// + /// Results for a query of this type are stored in a Win32 SecPkgContext_Name structure. + /// + Names = 1, + + /// + /// Queries the name of the authenticating authority for the security context. + /// + /// + /// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure. + /// + Authority = 6, + } +} diff --git a/NSspi.csproj b/NSspi.csproj index b18a9bc..ddd141a 100644 --- a/NSspi.csproj +++ b/NSspi.csproj @@ -49,6 +49,8 @@ + + diff --git a/Program.cs b/Program.cs index 568679d..aea19f0 100644 --- a/Program.cs +++ b/Program.cs @@ -91,7 +91,16 @@ namespace NSspi if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; } } - + + + Console.Out.WriteLine( "Server authority: " + server.AuthorityName ); + Console.Out.WriteLine( "Server context user: " + server.ContextUserName ); + + Console.Out.WriteLine(); + + Console.Out.WriteLine( "Client authority: " + client.AuthorityName ); + Console.Out.WriteLine( "Client context user: " + client.ContextUserName ); + Console.Out.Flush(); } finally