_NTAuthentication.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Net / System / Net / _NTAuthentication.cs / 1 / _NTAuthentication.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net { 
    using System.Runtime.InteropServices; 
    using System.Diagnostics;
    using System.ComponentModel; 
    using System.Text;
    using System.Threading;
    using System.Globalization;
    using System.Security.Principal; 
    using System.Security.Permissions;
    using System.Net.Security; 
 
    // #define ISC_REQ_DELEGATE                0x00000001
    // #define ISC_REQ_MUTUAL_AUTH             0x00000002 
    // #define ISC_REQ_REPLAY_DETECT           0x00000004
    // #define ISC_REQ_SEQUENCE_DETECT         0x00000008
    // #define ISC_REQ_CONFIDENTIALITY         0x00000010
    // #define ISC_REQ_USE_SESSION_KEY         0x00000020 
    // #define ISC_REQ_PROMPT_FOR_CREDS        0x00000040
    // #define ISC_REQ_USE_SUPPLIED_CREDS      0x00000080 
    // #define ISC_REQ_ALLOCATE_MEMORY         0x00000100 
    // #define ISC_REQ_USE_DCE_STYLE           0x00000200
    // #define ISC_REQ_DATAGRAM                0x00000400 
    // #define ISC_REQ_CONNECTION              0x00000800
    // #define ISC_REQ_CALL_LEVEL              0x00001000
    // #define ISC_REQ_FRAGMENT_SUPPLIED       0x00002000
    // #define ISC_REQ_EXTENDED_ERROR          0x00004000 
    // #define ISC_REQ_STREAM                  0x00008000
    // #define ISC_REQ_INTEGRITY               0x00010000 
    // #define ISC_REQ_IDENTIFY                0x00020000 
    // #define ISC_REQ_NULL_SESSION            0x00040000
    // #define ISC_REQ_MANUAL_CRED_VALIDATION  0x00080000 
    // #define ISC_REQ_RESERVED1               0x00100000
    // #define ISC_REQ_FRAGMENT_TO_FIT         0x00200000
    // #define ISC_REQ_HTTP                    0x10000000
 
    // #define ASC_REQ_DELEGATE                0x00000001
    // #define ASC_REQ_MUTUAL_AUTH             0x00000002 
    // #define ASC_REQ_REPLAY_DETECT           0x00000004 
    // #define ASC_REQ_SEQUENCE_DETECT         0x00000008
    // #define ASC_REQ_CONFIDENTIALITY         0x00000010 
    // #define ASC_REQ_USE_SESSION_KEY         0x00000020
    // #define ASC_REQ_ALLOCATE_MEMORY         0x00000100
    // #define ASC_REQ_USE_DCE_STYLE           0x00000200
    // #define ASC_REQ_DATAGRAM                0x00000400 
    // #define ASC_REQ_CONNECTION              0x00000800
    // #define ASC_REQ_CALL_LEVEL              0x00001000 
    // #define ASC_REQ_EXTENDED_ERROR          0x00008000 
    // #define ASC_REQ_STREAM                  0x00010000
    // #define ASC_REQ_INTEGRITY               0x00020000 
    // #define ASC_REQ_LICENSING               0x00040000
    // #define ASC_REQ_IDENTIFY                0x00080000
    // #define ASC_REQ_ALLOW_NULL_SESSION      0x00100000
    // #define ASC_REQ_ALLOW_NON_USER_LOGONS   0x00200000 
    // #define ASC_REQ_ALLOW_CONTEXT_REPLAY    0x00400000
    // #define ASC_REQ_FRAGMENT_TO_FIT         0x00800000 
    // #define ASC_REQ_FRAGMENT_SUPPLIED       0x00002000 
    // #define ASC_REQ_NO_TOKEN                0x01000000
    // #define ASC_REQ_HTTP                    0x10000000 

    [Flags]
    internal enum ContextFlags {
        Zero            = 0, 
        // The server in the transport application can
        // build new security contexts impersonating the 
        // client that will be accepted by other servers 
        // as the client's contexts.
        Delegate        = 0x00000001, 
        // The communicating parties must authenticate
        // their identities to each other. Without MutualAuth,
        // the client authenticates its identity to the server.
        // With MutualAuth, the server also must authenticate 
        // its identity to the client.
        MutualAuth      = 0x00000002, 
        // The security package detects replayed packets and 
        // notifies the caller if a packet has been replayed.
        // The use of this flag implies all of the conditions 
        // specified by the Integrity flag.
        ReplayDetect    = 0x00000004,
        // The context must be allowed to detect out-of-order
        // delivery of packets later through the message support 
        // functions. Use of this flag implies all of the
        // conditions specified by the Integrity flag. 
        SequenceDetect  = 0x00000008, 
        // The context must protect data while in transit.
        // Confidentiality is supported for NTLM with Microsoft 
        // Windows NT version 4.0, SP4 and later and with the
        // Kerberos protocol in Microsoft Windows 2000 and later.
        Confidentiality = 0x00000010,
        UseSessionKey   = 0x00000020, 
        AllocateMemory  = 0x00000100,
 
        // Connection semantics must be used. 
        Connection      = 0x00000800,
 
        // Client applications requiring extended error messages specify the
        // ISC_REQ_EXTENDED_ERROR flag when calling the InitializeSecurityContext
        // Server applications requiring extended error messages set
        // the ASC_REQ_EXTENDED_ERROR flag when calling AcceptSecurityContext. 
        InitExtendedError    = 0x00004000,
        AcceptExtendedError  = 0x00008000, 
        // A transport application requests stream semantics 
        // by setting the ISC_REQ_STREAM and ASC_REQ_STREAM
        // flags in the calls to the InitializeSecurityContext 
        // and AcceptSecurityContext functions
        InitStream          = 0x00008000,
        AcceptStream        = 0x00010000,
        // Buffer integrity can be verified; however, replayed 
        // and out-of-sequence messages will not be detected
        InitIntegrity       = 0x00010000,       // ISC_REQ_INTEGRITY 
        AcceptIntegrity     = 0x00020000,       // ASC_REQ_INTEGRITY 

        InitManualCredValidation    = 0x00080000,   // ISC_REQ_MANUAL_CRED_VALIDATION 
        InitUseSuppliedCreds        = 0x00000080,   // ISC_REQ_USE_SUPPLIED_CREDS
        InitIdentify                = 0x00020000,   // ISC_REQ_IDENTIFY
        AcceptIdentify              = 0x00080000,   // ASC_REQ_IDENTIFY
 
        InitHttp                    = 0x10000000,   // ISC_REQ_HTTP
        AcceptHttp                  = 0x10000000,   // ASC_REQ_HTTP 
    } 

    internal class NTAuthentication { 

        static private int s_UniqueGroupId = 1;
        static private ContextCallback s_InitializeCallback = new ContextCallback(InitializeCallback);
 
        private bool m_IsServer;
 
        private SafeFreeCredentials m_CredentialsHandle; 
        private SafeDeleteContext   m_SecurityContext;
        private string m_Spn; 

        private int m_TokenSize;
        private ContextFlags m_RequestedContextFlags;
        private ContextFlags m_ContextFlags; 
        private string m_UniqueUserId;
 
        private bool m_IsCompleted; 
        private string m_ProtocolName;
        private SecSizes m_Sizes; 
        private string m_LastProtocolName;
        private string m_Package;

        // 
        // Properties
        // 
        internal string UniqueUserId { 
            get {
                return m_UniqueUserId; 
            }
        }

        // The semantic of this propoerty is "Don't call me again". 
        // It can be completed either with success or error
        // The latest case is signalled by IsValidContext==false 
        internal bool IsCompleted { 
            get {
                return m_IsCompleted; 
            }
        }

        internal bool IsValidContext { 
            get {
                return !(m_SecurityContext == null || m_SecurityContext.IsInvalid); 
            } 
        }
 
        internal string AssociatedName {
            get {
                if (!(IsValidContext && IsCompleted))
                    throw new Win32Exception((int)SecurityStatus.InvalidHandle); 

                string name = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.Names) as string; 
                GlobalLog.Print("NTAuthentication: The context is associated with [" + name + "]"); 
                return name;
            } 
        }

        internal bool IsConfidentialityFlag {
            get { 
                return (m_ContextFlags & ContextFlags.Confidentiality) != 0;
            } 
        } 

        internal bool IsIntegrityFlag { 
            get {
                return (m_ContextFlags & (m_IsServer?ContextFlags.AcceptIntegrity:ContextFlags.InitIntegrity)) != 0;
            }
        } 

        internal bool IsMutualAuthFlag { 
            get { 
                return (m_ContextFlags & ContextFlags.MutualAuth) != 0;
            } 
        }

        internal bool IsDelegationFlag {
            get { 
                return (m_ContextFlags & ContextFlags.Delegate) != 0;
            } 
        } 

        internal bool IsIdentifyFlag { 
            get {
                return (m_ContextFlags & (m_IsServer?ContextFlags.AcceptIdentify:ContextFlags.InitIdentify)) != 0;
            }
        } 

        internal string Spn { 
            get { 
                return m_Spn;
            } 
        }

        //
        // True indicates this instance is for Server and will use AcceptSecurityContext SSPI API 
        //
        internal bool IsServer { 
            get { 
                return m_IsServer;
            } 
        }

        //
        internal bool IsKerberos 
        {
            get { 
                if (m_LastProtocolName  == null) 
                    m_LastProtocolName = ProtocolName;
 
                return (object) m_LastProtocolName == (object) NegotiationInfoClass.Kerberos;
            }
        }
        internal bool IsNTLM 
        {
            get { 
                if (m_LastProtocolName  == null) 
                    m_LastProtocolName = ProtocolName;
 
                return (object) m_LastProtocolName == (object) NegotiationInfoClass.NTLM;
            }
        }
 
        internal string Package
        { 
            get 
            {
                return m_Package; 
            }
        }

        internal string ProtocolName { 
            get {
                // NB: May return string.Empty if the auth is not done yet or failed 
                if (m_ProtocolName==null) 
                {
                    NegotiationInfoClass negotiationInfo = null; 

                    if (IsValidContext)
                    {
                        negotiationInfo = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.NegotiationInfo) as NegotiationInfoClass; 
                        if (IsCompleted) {
                            if (negotiationInfo == null) 
                            { 
                                // Win9x workaround for not supported query NegotiateInfo context attribute
                                if(ComNetOS.IsWin9x) 
                                {
                                    m_ProtocolName = NegotiationInfoClass.NTLM;
                                    return m_ProtocolName;
                                } 
                            }
                            else 
                            { 
                                //cache it only when it's completed
                                m_ProtocolName = negotiationInfo.AuthenticationPackage; 
                            }
                        }
                    }
                    return negotiationInfo == null? string.Empty: negotiationInfo.AuthenticationPackage; 
                }
                return m_ProtocolName; 
            } 
        }
 
        internal SecSizes Sizes {
            get {
                GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::MaxDataSize|The context is not completed or invalid.", ValidationHelper.HashString(this));
                if (m_Sizes == null) { 
                    m_Sizes = SSPIWrapper.QueryContextAttributes(
                                  GlobalSSPI.SSPIAuth, 
                                  m_SecurityContext, 
                                  ContextAttribute.Sizes
                                  ) as SecSizes; 
                }
                return m_Sizes;
            }
        } 

        // 
        // .Ctors 
        //
 
        //
        // Use only for client HTTP authentication
        //
        internal NTAuthentication(string package, NetworkCredential networkCredential, string spn, WebRequest request) : 
            this(false, package, networkCredential, spn, GetHttpContextFlags(request), request.GetWritingContext())
        { 
            // 
            //  In order to prevent a race condition where one request could
            //  steal a connection from another request, before a handshake is 
            //  complete, we create a new Group for each authentication request.
            //
            if (package == NtlmClient.AuthType || package == NegotiateClient.AuthType) {
                m_UniqueUserId = (Interlocked.Increment(ref s_UniqueGroupId)).ToString(NumberFormatInfo.InvariantInfo) + m_UniqueUserId; 
            }
        } 
        // 
        private static ContextFlags GetHttpContextFlags(WebRequest request)
        { 
            ContextFlags contextFlags = ContextFlags.Connection | ContextFlags.Confidentiality | ContextFlags.ReplayDetect | ContextFlags.SequenceDetect;

            if (request.ImpersonationLevel == TokenImpersonationLevel.Anonymous)
                throw new NotSupportedException(SR.GetString(SR.net_auth_no_anonymous_support)); 
            else if(request.ImpersonationLevel == TokenImpersonationLevel.Identification)
                contextFlags |= ContextFlags.InitIdentify; 
            else if(request.ImpersonationLevel == TokenImpersonationLevel.Delegation) 
                contextFlags |= ContextFlags.Delegate;
 
            if (request.AuthenticationLevel == AuthenticationLevel.MutualAuthRequested || request.AuthenticationLevel == AuthenticationLevel.MutualAuthRequired)
                contextFlags |= ContextFlags.MutualAuth;

            return contextFlags; 
        }
 
        // 
        // This constructor is for a general (non-HTTP) authentication handshake using SSPI
        // Works for both client and server sides. 
        //
        // Security: we may need to impersonate on user behalf as to temporarily restore original thread token.
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
        internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ContextAwareResult context) 
        {
            // 
            // check if we're using DefaultCredentials 
            //
            if (credential is SystemNetworkCredential && ComNetOS.IsWinNt) 
            {
                //
#if DEBUG
                GlobalLog.Assert(context == null || context.IdentityRequested, "NTAuthentication#{0}::.ctor|Authentication required when it wasn't expected.  (Maybe Credentials was changed on another thread?)", ValidationHelper.HashString(this)); 
#endif
 
                WindowsIdentity w = context == null ? null : context.Identity; 
                try
                { 
                    IDisposable ctx = w == null ? null : w.Impersonate();
                    if (ctx != null)
                    {
                        using (ctx) 
                        {
                            Initialize(isServer, package, credential, spn, requestedContextFlags); 
                        } 
                    }
                    else 
                    {
                        ExecutionContext x = context == null ? null : context.ContextCopy;
                        if (x == null)
                        { 
                            Initialize(isServer, package, credential, spn, requestedContextFlags);
                        } 
                        else 
                        {
                            ExecutionContext.Run(x, s_InitializeCallback, new InitializeCallbackContext(this, isServer, package, credential, spn, requestedContextFlags)); 
                        }
                    }
                }
                catch 
                {
                    // Prevent the impersonation from leaking to upstack exception filters. 
                    throw; 
                }
            } 
            else
            {
                Initialize(isServer, package, credential, spn, requestedContextFlags);
            } 
        }
 
        // 
        // This overload does not attmept to impersonate because the caller either did it already or the original thread context is still preserved
        // 
        internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags) {
            Initialize(isServer, package, credential, spn, requestedContextFlags);
        }
 
        //
        // This overload always uses the default credentials for the process. 
        // 
        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
        internal NTAuthentication(bool isServer, string package, string spn, ContextFlags requestedContextFlags) 
        {
            try
            {
                using (WindowsIdentity.Impersonate(IntPtr.Zero)) 
                {
                    Initialize(isServer, package, SystemNetworkCredential.defaultCredential, spn, requestedContextFlags); 
                } 
            }
            catch 
            {
                // Avoid exception filter attacks.
                throw;
            } 
        }
 
        private class InitializeCallbackContext 
        {
            internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags) 
            {
                this.thisPtr = thisPtr;
                this.isServer = isServer;
                this.package = package; 
                this.credential = credential;
                this.spn = spn; 
                this.requestedContextFlags = requestedContextFlags; 
            }
 
            internal readonly NTAuthentication thisPtr;
            internal readonly bool isServer;
            internal readonly string package;
            internal readonly NetworkCredential credential; 
            internal readonly string spn;
            internal readonly ContextFlags requestedContextFlags; 
        } 

        private static void InitializeCallback(object state) 
        {
            InitializeCallbackContext context = (InitializeCallbackContext)state;
            context.thisPtr.Initialize(context.isServer, context.package, context.credential, context.spn, context.requestedContextFlags);
        } 

        // 
        private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags) { 
            GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor() package:" + ValidationHelper.ToString(package) + " spn:" + ValidationHelper.ToString(spn) + " flags :" + requestedContextFlags.ToString());
            m_TokenSize = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; 
            m_IsServer = isServer;
            m_Spn = spn;
            m_SecurityContext = null;
            m_RequestedContextFlags = requestedContextFlags; 
            m_Package = package;
 
            GlobalLog.Print("Peer SPN-> '" + m_Spn + "'"); 
            //
            // check if we're using DefaultCredentials 
            //
            if (credential is SystemNetworkCredential)
            {
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using DefaultCredentials"); 
                m_CredentialsHandle = SSPIWrapper.AcquireDefaultCredential(
                                                    GlobalSSPI.SSPIAuth, 
                                                    package, 
                                                    (m_IsServer? CredentialUse.Inbound: CredentialUse.Outbound));
                m_UniqueUserId = "/S"; // save off for unique connection marking ONLY used by HTTP client 
            }
            else
            {
 
                //
                // we're not using DefaultCredentials, we need a 
                // AuthIdentity struct to contain credentials 
                // SECREVIEW:
                // we'll save username/domain in temp strings, to avoid decrypting multiple times. 
                // password is only used once
                //
                string username = credential.InternalGetUserName();
 
                string domain = credential.InternalGetDomain();
                // ATTN: 
                // NetworkCredential class does not differentiate between null and "" but SSPI packages treat these cases differently 
                // For NTLM we want to keep "" for Wdigest.Dll we should use null.
                AuthIdentity authIdentity = new AuthIdentity(username, credential.InternalGetPassword(), (object)package == (object)NegotiationInfoClass.WDigest && (domain == null || domain.Length == 0)? null: domain); 

                m_UniqueUserId = domain + "/" + username + "/U"; // save off for unique connection marking ONLY used by HTTP client

                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using authIdentity:" + authIdentity.ToString()); 

                m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle( 
                                                    GlobalSSPI.SSPIAuth, 
                                                    package,
                                                    (m_IsServer? CredentialUse.Inbound: CredentialUse.Outbound), 
                                                    ref authIdentity
                                                    );
            }
        } 

        // 
        // Methods 
        //
 

        // This will return an client token when conducted authentication on server side'
        // This token can be used ofr impersanation
        // We use it to create a WindowsIdentity and hand it out to the server app. 
        internal SafeCloseHandle GetContextToken(out SecurityStatus status)
        { 
            GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", ValidationHelper.HashString(this)); 
            GlobalLog.Assert(IsServer, "NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", ValidationHelper.HashString(this));
 
            if (!IsValidContext) {
                throw new Win32Exception((int)SecurityStatus.InvalidHandle);
            }
 

            SafeCloseHandle token = null; 
            status = (SecurityStatus) SSPIWrapper.QuerySecurityContextToken( 
                GlobalSSPI.SSPIAuth,
                m_SecurityContext, 
                out token);

            return token;
        } 

        internal SafeCloseHandle GetContextToken() 
        { 
            SecurityStatus status;
            SafeCloseHandle token = GetContextToken(out status); 
            if (status != SecurityStatus.OK) {
                throw new Win32Exception((int)status);
            }
            return token; 
        }
 
        internal void CloseContext() 
        {
            if (m_SecurityContext != null && !m_SecurityContext.IsClosed) 
                m_SecurityContext.Close();
        }

 
        //
        // NTAuth::GetOutgoingBlob() 
        // Created:   12-01-1999: L.M. 
        // Description:
        // Accepts a base64 encoded incoming security blob and returns 
        // a base 64 encoded outgoing security blob
        //
        // This method is for HttpWebRequest usage only as it has semantic bound to it
        internal string GetOutgoingBlob(string incomingBlob) { 
            GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", incomingBlob);
            byte[] decodedIncomingBlob = null; 
            if (incomingBlob != null && incomingBlob.Length > 0) { 
                decodedIncomingBlob = Convert.FromBase64String(incomingBlob);
            } 
            byte[] decodedOutgoingBlob = null;

            if ((IsValidContext || IsCompleted) && decodedIncomingBlob == null) {
                // we tried auth previously, now we got a null blob, we're done. this happens 
                // with Kerberos & valid credentials on the domain but no ACLs on the resource
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() null blob AND m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.ToString() + "]"); 
                m_IsCompleted = true; 
            }
            else { 
                SecurityStatus statusCode;
#if TRAVE
                try {
#endif 
                    decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, true, out statusCode);
#if TRAVE 
                } catch (Exception exception) { 
                    if (NclUtilities.IsFatal(exception)) throw;
 
                    GlobalLog.LeaveException("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", exception);
                    throw;
                }
#endif 
            }
 
            string outgoingBlob = null; 
            if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) {
                outgoingBlob = Convert.ToBase64String(decodedOutgoingBlob); 
            }

            //This is only for HttpWebRequest that does not need security context anymore
            if (IsCompleted) 
            {
                string name = ProtocolName; // cache the only info needed from a completed context before closing it 
                CloseContext(); 
            }
            GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", outgoingBlob); 
            return outgoingBlob;
        }

        // NTAuth::GetOutgoingBlob() 
        // Created:   12-01-1999: L.M.
        // Description: 
        // Accepts an incoming binary security blob  and returns 
        // an outgoing binary security blob
        internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode) 
        {
            GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes");

            SecurityBuffer inSecurityBuffer = null; 
            if (incomingBlob != null) {
//                GlobalLog.Print("in blob = "); 
//                GlobalLog.Dump(incomingBlob); 
                inSecurityBuffer = new SecurityBuffer(incomingBlob,BufferType.Token);
            } 

            SecurityBuffer outSecurityBuffer = new SecurityBuffer(m_TokenSize, BufferType.Token);

            bool firstTime = m_SecurityContext == null; 
            try {
                if (!m_IsServer) { 
                    // client session 
                    statusCode = (SecurityStatus) SSPIWrapper.InitializeSecurityContext(
                        GlobalSSPI.SSPIAuth, 
                        ref m_CredentialsHandle,
                        ref m_SecurityContext,
                        m_Spn,
                        m_RequestedContextFlags, 
                        Endianness.Network,
                        inSecurityBuffer, 
                        outSecurityBuffer, 
                        ref m_ContextFlags );
 
                    GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");

                    if (statusCode == SecurityStatus.CompleteNeeded)
                    { 
                        SecurityBuffer[] inSecurityBuffers = new SecurityBuffer[1];
                        inSecurityBuffers[0] = outSecurityBuffer; 
 
                        statusCode = (SecurityStatus) SSPIWrapper.CompleteAuthToken(
                            GlobalSSPI.SSPIAuth, 
                            ref m_SecurityContext,
                            inSecurityBuffers );

                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); 
                        outSecurityBuffer.token = null;
                    } 
                } 
                else {
                    // server session 
                    statusCode = (SecurityStatus) SSPIWrapper.AcceptSecurityContext(
                        GlobalSSPI.SSPIAuth,
                        ref m_CredentialsHandle,
                        ref m_SecurityContext, 
                        m_RequestedContextFlags,
                        Endianness.Network, 
                        inSecurityBuffer, 
                        outSecurityBuffer,
                        ref m_ContextFlags ); 

                    GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                }
            } 
            finally {
                // 
                // Assuming the ISC or ASC has referenced the credential on the first successful call, 
                // we want to decrement the effective ref count by "disposing" it.
                // The real dispose will happen when the security context is closed. 
                // Note if the first call was not successfull the handle is physically destroyed here
                //
              if (firstTime && m_CredentialsHandle != null)
                  m_CredentialsHandle.Close(); 
            }
 
 
          if (((int) statusCode & unchecked((int) 0x80000000)) != 0)
          { 
                CloseContext();
                m_IsCompleted = true;
                if (throwOnError) {
                    Win32Exception exception = new Win32Exception((int) statusCode); 
                    GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception);
                    throw exception; 
                } 
                GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                return null; 
            }
            else if (firstTime && m_CredentialsHandle != null)
            {
                // cache until it is pushed out by newly incoming handles 
                SSPIHandleCache.CacheCredential(m_CredentialsHandle);
            } 
 
            // the return value from SSPI will tell us correctly if the
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm 
            // we also have to consider the case in which SSPI formed a new context, in this case we're done as well.
            if (statusCode == SecurityStatus.OK)
            {
                // we're sucessfully done 
                GlobalLog.Assert(statusCode == SecurityStatus.OK, "NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", ValidationHelper.HashString(this), (int)statusCode, statusCode, ValidationHelper.HashString(m_SecurityContext), ValidationHelper.ToString(m_SecurityContext));
                m_IsCompleted = true; 
            } 
            else {
                // we need to continue 
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:" + ValidationHelper.ToString(m_SecurityContext) + "]");
            }
//            GlobalLog.Print("out token = " + outSecurityBuffer.ToString());
//            GlobalLog.Dump(outSecurityBuffer.token); 
            GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString());
            return outSecurityBuffer.token; 
        } 

        // for Server side (IIS 6.0) see: \\netindex\Sources\inetsrv\iis\iisrearc\iisplus\ulw3\digestprovider.cxx 
        // for Client side (HTTP.SYS) see: \\netindex\Sources\net\http\sys\ucauth.c
        internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode)
        {
            GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", incomingBlob); 

            m_RequestedContextFlags |= (ContextFlags.AcceptHttp | ContextFlags.ReplayDetect | ContextFlags.SequenceDetect); 
 
            // second time call with 3 incoming buffers to select HTTP client.
            // we should get back a SecurityStatus.OK and a non null outgoingBlob. 
            SecurityBuffer[] inSecurityBuffers = null;
            SecurityBuffer outSecurityBuffer = new SecurityBuffer(m_TokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token);

            bool firstTime = m_SecurityContext == null; 
            try {
                if (!m_IsServer) { 
                    // client session 

                    if (!isClientPreAuth) { 
                        // make sure we don't require this flag or we'd drop qop="auth"
                        m_RequestedContextFlags &= ~ContextFlags.Confidentiality;

                        if (incomingBlob!=null) { 
                            inSecurityBuffers = new SecurityBuffer[] {
                                new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), BufferType.Token), 
                                new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), 
                                new SecurityBuffer(null, BufferType.Parameters),
                            }; 
                        }

                        statusCode = (SecurityStatus) SSPIWrapper.InitializeSecurityContext(
                            GlobalSSPI.SSPIAuth, 
                            m_CredentialsHandle,
                            ref m_SecurityContext, 
                            m_Spn, // this must match the Uri in the HTTP status line for the current request 
                            m_RequestedContextFlags,
                            Endianness.Network, 
                            inSecurityBuffers,
                            outSecurityBuffer,
                            ref m_ContextFlags );
 
                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                    } 
                    else { 
#if WDIGEST_PREAUTH
                        inSecurityBuffers = new SecurityBuffer[] { 
                            new SecurityBuffer(null, BufferType.Token),
                            new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters),
                            new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters),
                            new SecurityBuffer(null, BufferType.Parameters), 
                            outSecurityBuffer,
                        }; 
 
                        statusCode = (SecurityStatus) SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, inSecurityBuffers, 0);
 
                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.MakeSignature() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
#else
                        statusCode = SecurityStatus.OK;
                        GlobalLog.Assert("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob()", "Invalid code path."); 
#endif
                    } 
                } 
                else {
                    // server session 

                    inSecurityBuffers = new SecurityBuffer[] {
                        incomingBlob==null ? null : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), BufferType.Token),
                        requestMethod==null ? null : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), 
                        requestedUri==null ? null : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters),
                        null, // BufferType.Parameters 
                        realm==null ? null : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters), 
                    };
 
                    statusCode = (SecurityStatus) SSPIWrapper.AcceptSecurityContext(
                        GlobalSSPI.SSPIAuth,
                        m_CredentialsHandle,
                        ref m_SecurityContext, 
                        m_RequestedContextFlags,
                        Endianness.Network, 
                        inSecurityBuffers, 
                        outSecurityBuffer,
                        ref m_ContextFlags ); 

                    GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");

                    if (statusCode == SecurityStatus.CompleteNeeded) 
                    {
                        inSecurityBuffers[4] = outSecurityBuffer; 
 
                        statusCode = (SecurityStatus) SSPIWrapper.CompleteAuthToken(
                                GlobalSSPI.SSPIAuth, 
                                ref m_SecurityContext,
                                inSecurityBuffers );

                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); 

                        outSecurityBuffer.token = null; 
                    } 
                }
            } 
            finally {
                //
                // Assuming the ISC or ASC has referenced the credential on the first successful call,
                // we want to decrement the effective ref count by "disposing" it. 
                // The real dispose will happen when the security context is closed.
                // Note if the first call was not successfull the handle is physically destroyed here 
                // 
              if (firstTime && m_CredentialsHandle != null)
                  m_CredentialsHandle.Close(); 
            }


            if (((int) statusCode & unchecked((int) 0x80000000)) != 0) 
            {
                CloseContext(); 
                if (throwOnError) { 
                    Win32Exception exception = new Win32Exception((int) statusCode);
                    GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "Win32Exception:" + exception); 
                    throw exception;
                }
                GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "null statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                return null; 
            }
            else if (firstTime && m_CredentialsHandle != null) 
            { 
                // cache until it is pushed out by newly incoming handles
                SSPIHandleCache.CacheCredential(m_CredentialsHandle); 
            }


            // the return value from SSPI will tell us correctly if the 
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
            if (statusCode == SecurityStatus.OK) 
            { 
                // we're done, cleanup
                m_IsCompleted = true; 
            }
            else {
                // we need to continue
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() need continue statusCode:[0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:" + ValidationHelper.ToString(m_SecurityContext) + "]"); 
            }
            GlobalLog.Print("out token = " + outSecurityBuffer.ToString()); 
            GlobalLog.Dump(outSecurityBuffer.token); 
            GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() IsCompleted:" + IsCompleted.ToString());
 
            byte[] decodedOutgoingBlob = outSecurityBuffer.token;
            string outgoingBlob = null;
            if (decodedOutgoingBlob!=null && decodedOutgoingBlob.Length>0) {
                outgoingBlob = WebHeaderCollection.HeaderEncoding.GetString(decodedOutgoingBlob, 0, outSecurityBuffer.size); 
            }
            GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", outgoingBlob); 
            return outgoingBlob; 
        }
 
        internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber) {
            SecSizes sizes = Sizes;

            try 
            {
                int maxCount = checked(Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); 
 
                if (count > maxCount || count < 0)
                { 
                    throw new ArgumentOutOfRangeException("count", SR.GetString(SR.net_io_out_range, maxCount));
                }
            }
            catch(Exception e) 
            {
                if (!NclUtilities.IsFatal(e)){ 
                    GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::Encrypt", "Arguments out of range."); 
                }
                throw; 
            }

            int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize;
            if (output == null || output.Length < resultSize+4) 
            {
                output = new byte[resultSize+4]; 
            } 

            // make a copy of user data for in-place encryption 
            Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count);

            // prepare buffers TOKEN(signautre), DATA and Padding
            SecurityBuffer[] securityBuffer = new SecurityBuffer[3]; 
            securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, BufferType.Token);
            securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, BufferType.Data); 
            securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, BufferType.Padding); 

            int errorCode; 
            if (IsConfidentialityFlag)
            {
                errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, sequenceNumber);
            } 
            else
            { 
                if (IsNTLM) 
                    securityBuffer[1].type |= BufferType.ReadOnlyFlag;
                errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, 0); 
            }


            if (errorCode != 0) { 
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode); 
            } 

            // Compacting the result... 
            resultSize = securityBuffer[0].size;
            bool forceCopy = false;
            if (resultSize != sizes.SecurityTrailer)
            { 
                forceCopy = true;
                Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size); 
            } 

            resultSize += securityBuffer[1].size; 
            if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer)))
                Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size);

            resultSize += securityBuffer[2].size; 

            unchecked { 
                output[0] = (byte)((resultSize) & 0xFF); 
                output[1] = (byte)(((resultSize)>>8) & 0xFF);
                output[2] = (byte)(((resultSize)>>16) & 0xFF); 
                output[3] = (byte)(((resultSize)>>24) & 0xFF);
            }
            return resultSize+4;
        } 

        internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) 
        { 
            if (offset < 0 || offset > (payload == null ? 0 : payload.Length))
            { 
                GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt", "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset");
            }
            if (count < 0 || count > (payload == null ? 0 : payload.Length - offset)) 
            {
                GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt", "Argument 'count' out of range."); 
                throw new ArgumentOutOfRangeException("count"); 
            }
 
            if (IsNTLM)
                return DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber);

            // 
            // Kerberos and up
            // 
 
            SecurityBuffer[] securityBuffer = new SecurityBuffer[2];
            securityBuffer[0] = new SecurityBuffer(payload, offset, count, BufferType.Stream); 
            securityBuffer[1] = new SecurityBuffer(0, BufferType.Data);

            int errorCode;
            if (IsConfidentialityFlag) 
            {
                errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber); 
            } 
            else
            { 
                errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber);
            }

            if (errorCode != 0) 
            {
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); 
                throw new Win32Exception(errorCode); 
            }
 
            if (securityBuffer[1].type != BufferType.Data)
                throw new InternalException();

            newOffset = securityBuffer[1].offset; 
            return securityBuffer[1].size;
 
        } 
        //
        private int DecryptNtlm(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) 
        {
            // For the most part the arguments are verified in Encrypt().
            if (count < 16)
            { 
                GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::DecryptNtlm", "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count"); 
            } 

            SecurityBuffer[] securityBuffer = new SecurityBuffer[2]; 
            securityBuffer[0] = new SecurityBuffer(payload, offset, 16, BufferType.Token);
            securityBuffer[1] = new SecurityBuffer(payload, offset + 16, count-16, BufferType.Data);

            int errorCode; 
            BufferType realDataType = BufferType.Data;
 
            if (IsConfidentialityFlag) 
            {
                errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber); 
            }
            else
            {
                realDataType |= BufferType.ReadOnlyFlag; 
                securityBuffer[1].type = realDataType;
                errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber); 
            } 

            if (errorCode != 0) 
            {
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode);
            } 

            if (securityBuffer[1].type != realDataType) 
                throw new InternalException(); 

            newOffset = securityBuffer[1].offset; 
            return securityBuffer[1].size;
        }

        // 
        // VerifySignature
        // 
        // Adapted from Decrypt method above as a more generic message 
        // signature verify method for SMTP AUTH GSSAPI (SASL).
        // Decrypt method, used NegotiateStream, couldn't be used due 
        // to special cases for NTLM.
        //
        // See SmtpNegotiateAuthenticationModule class for caller.
        // 
        internal int VerifySignature(byte[] buffer, int offset, int count) {
 
            // validate offset within length 
            if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) {
                GlobalLog.Assert( 
                            false,
                            "NTAuthentication#" +
                            ValidationHelper.HashString(this) +
                            "::VerifySignature", 
                            "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset"); 
            } 

            // validate count within offset and end of buffer 
            if (count < 0 ||
                count > (buffer == null ? 0 : buffer.Length - offset)) {
                GlobalLog.Assert(
                            false, 
                            "NTAuthentication#" +
                            ValidationHelper.HashString(this) + 
                            "::VerifySignature", 
                            "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count"); 
            }

            // setup security buffers for ssp call
            // one points at signed data 
            // two will receive payload if signature is valid
            SecurityBuffer[] securityBuffer = new SecurityBuffer[2]; 
            securityBuffer[0] = 
                new SecurityBuffer(buffer, offset, count, BufferType.Stream);
            securityBuffer[1] = new SecurityBuffer(0, BufferType.Data); 

            // call SSP function
            int errorCode = SSPIWrapper.VerifySignature(
                                GlobalSSPI.SSPIAuth, 
                                m_SecurityContext,
                                securityBuffer, 
                                0); 

            // throw if error 
            if (errorCode != 0)
            {
                GlobalLog.Print(
                            "NTAuthentication#" + 
                            ValidationHelper.HashString(this) +
                            "::VerifySignature() threw Error = " + 
                            errorCode.ToString("x", 
                                NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode); 
            }

            // not sure why this is here - retained from Encrypt code above
            if (securityBuffer[1].type != BufferType.Data) 
                throw new InternalException();
 
            // return validated payload size 
            return securityBuffer[1].size;
        } 

        //
        // MakeSignature
        // 
        // Adapted from Encrypt method above as a more generic message
        // signing method for SMTP AUTH GSSAPI (SASL). 
        // Encrypt method, used for NegotiateStream, put size at head of 
        // message.  Don't need that
        // 
        // See SmtpNegotiateAuthenticationModule class for caller.
        //
        internal int MakeSignature(
                        byte[] buffer, 
                        int offset,
                        int count, 
                        ref byte[] output) { 
            SecSizes sizes = Sizes;
 

            // alloc new output buffer if not supplied or too small
            int resultSize = count + sizes.MaxSignature;
            if (output == null || output.Length < resultSize) 
            {
                output = new byte[resultSize]; 
            } 

            // make a copy of user data for in-place encryption 
            Buffer.BlockCopy(buffer, offset, output, sizes.MaxSignature, count);

            // setup security buffers for ssp call
            SecurityBuffer[] securityBuffer = new SecurityBuffer[2]; 
            securityBuffer[0] = new SecurityBuffer(output, 0, sizes.MaxSignature, BufferType.Token);
            securityBuffer[1] = new SecurityBuffer(output, sizes.MaxSignature, count, BufferType.Data); 
 
            // call SSP Function
            int errorCode = SSPIWrapper.MakeSignature( 
                                GlobalSSPI.SSPIAuth,
                                m_SecurityContext,
                                securityBuffer,
                                0); 

            // throw if error 
            if (errorCode != 0) { 
                GlobalLog.Print(
                    "NTAuthentication#" + 
                    ValidationHelper.HashString(this) +
                    "::Encrypt() throw Error = " +
                    errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode); 
            }
 
            // return signed size 
            return securityBuffer[0].size + securityBuffer[1].size;
        } 
    }

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    internal struct AuthIdentity { 
        // see SEC_WINNT_AUTH_IDENTITY_W
        internal string UserName; 
        internal int UserNameLength; 
        internal string Domain;
        internal int DomainLength; 
        internal string Password;
        internal int PasswordLength;
        internal int Flags;
 
        internal AuthIdentity(string userName, string password, string domain) {
            UserName = userName; 
            UserNameLength = userName==null ? 0 : userName.Length; 
            Password = password;
            PasswordLength = password==null ? 0 : password.Length; 
            Domain = domain;
            DomainLength = domain==null ? 0 : domain.Length;
            // Flags are 2 for Unicode and 1 for ANSI. We use 2 on NT and 1 on Win9x.
            Flags = ComNetOS.IsWin9x? 1: 2; 
        }
        public override string ToString() { 
            return ValidationHelper.ToString(Domain) + "\\" + ValidationHelper.ToString(UserName); 
        }
    } 

}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net { 
    using System.Runtime.InteropServices; 
    using System.Diagnostics;
    using System.ComponentModel; 
    using System.Text;
    using System.Threading;
    using System.Globalization;
    using System.Security.Principal; 
    using System.Security.Permissions;
    using System.Net.Security; 
 
    // #define ISC_REQ_DELEGATE                0x00000001
    // #define ISC_REQ_MUTUAL_AUTH             0x00000002 
    // #define ISC_REQ_REPLAY_DETECT           0x00000004
    // #define ISC_REQ_SEQUENCE_DETECT         0x00000008
    // #define ISC_REQ_CONFIDENTIALITY         0x00000010
    // #define ISC_REQ_USE_SESSION_KEY         0x00000020 
    // #define ISC_REQ_PROMPT_FOR_CREDS        0x00000040
    // #define ISC_REQ_USE_SUPPLIED_CREDS      0x00000080 
    // #define ISC_REQ_ALLOCATE_MEMORY         0x00000100 
    // #define ISC_REQ_USE_DCE_STYLE           0x00000200
    // #define ISC_REQ_DATAGRAM                0x00000400 
    // #define ISC_REQ_CONNECTION              0x00000800
    // #define ISC_REQ_CALL_LEVEL              0x00001000
    // #define ISC_REQ_FRAGMENT_SUPPLIED       0x00002000
    // #define ISC_REQ_EXTENDED_ERROR          0x00004000 
    // #define ISC_REQ_STREAM                  0x00008000
    // #define ISC_REQ_INTEGRITY               0x00010000 
    // #define ISC_REQ_IDENTIFY                0x00020000 
    // #define ISC_REQ_NULL_SESSION            0x00040000
    // #define ISC_REQ_MANUAL_CRED_VALIDATION  0x00080000 
    // #define ISC_REQ_RESERVED1               0x00100000
    // #define ISC_REQ_FRAGMENT_TO_FIT         0x00200000
    // #define ISC_REQ_HTTP                    0x10000000
 
    // #define ASC_REQ_DELEGATE                0x00000001
    // #define ASC_REQ_MUTUAL_AUTH             0x00000002 
    // #define ASC_REQ_REPLAY_DETECT           0x00000004 
    // #define ASC_REQ_SEQUENCE_DETECT         0x00000008
    // #define ASC_REQ_CONFIDENTIALITY         0x00000010 
    // #define ASC_REQ_USE_SESSION_KEY         0x00000020
    // #define ASC_REQ_ALLOCATE_MEMORY         0x00000100
    // #define ASC_REQ_USE_DCE_STYLE           0x00000200
    // #define ASC_REQ_DATAGRAM                0x00000400 
    // #define ASC_REQ_CONNECTION              0x00000800
    // #define ASC_REQ_CALL_LEVEL              0x00001000 
    // #define ASC_REQ_EXTENDED_ERROR          0x00008000 
    // #define ASC_REQ_STREAM                  0x00010000
    // #define ASC_REQ_INTEGRITY               0x00020000 
    // #define ASC_REQ_LICENSING               0x00040000
    // #define ASC_REQ_IDENTIFY                0x00080000
    // #define ASC_REQ_ALLOW_NULL_SESSION      0x00100000
    // #define ASC_REQ_ALLOW_NON_USER_LOGONS   0x00200000 
    // #define ASC_REQ_ALLOW_CONTEXT_REPLAY    0x00400000
    // #define ASC_REQ_FRAGMENT_TO_FIT         0x00800000 
    // #define ASC_REQ_FRAGMENT_SUPPLIED       0x00002000 
    // #define ASC_REQ_NO_TOKEN                0x01000000
    // #define ASC_REQ_HTTP                    0x10000000 

    [Flags]
    internal enum ContextFlags {
        Zero            = 0, 
        // The server in the transport application can
        // build new security contexts impersonating the 
        // client that will be accepted by other servers 
        // as the client's contexts.
        Delegate        = 0x00000001, 
        // The communicating parties must authenticate
        // their identities to each other. Without MutualAuth,
        // the client authenticates its identity to the server.
        // With MutualAuth, the server also must authenticate 
        // its identity to the client.
        MutualAuth      = 0x00000002, 
        // The security package detects replayed packets and 
        // notifies the caller if a packet has been replayed.
        // The use of this flag implies all of the conditions 
        // specified by the Integrity flag.
        ReplayDetect    = 0x00000004,
        // The context must be allowed to detect out-of-order
        // delivery of packets later through the message support 
        // functions. Use of this flag implies all of the
        // conditions specified by the Integrity flag. 
        SequenceDetect  = 0x00000008, 
        // The context must protect data while in transit.
        // Confidentiality is supported for NTLM with Microsoft 
        // Windows NT version 4.0, SP4 and later and with the
        // Kerberos protocol in Microsoft Windows 2000 and later.
        Confidentiality = 0x00000010,
        UseSessionKey   = 0x00000020, 
        AllocateMemory  = 0x00000100,
 
        // Connection semantics must be used. 
        Connection      = 0x00000800,
 
        // Client applications requiring extended error messages specify the
        // ISC_REQ_EXTENDED_ERROR flag when calling the InitializeSecurityContext
        // Server applications requiring extended error messages set
        // the ASC_REQ_EXTENDED_ERROR flag when calling AcceptSecurityContext. 
        InitExtendedError    = 0x00004000,
        AcceptExtendedError  = 0x00008000, 
        // A transport application requests stream semantics 
        // by setting the ISC_REQ_STREAM and ASC_REQ_STREAM
        // flags in the calls to the InitializeSecurityContext 
        // and AcceptSecurityContext functions
        InitStream          = 0x00008000,
        AcceptStream        = 0x00010000,
        // Buffer integrity can be verified; however, replayed 
        // and out-of-sequence messages will not be detected
        InitIntegrity       = 0x00010000,       // ISC_REQ_INTEGRITY 
        AcceptIntegrity     = 0x00020000,       // ASC_REQ_INTEGRITY 

        InitManualCredValidation    = 0x00080000,   // ISC_REQ_MANUAL_CRED_VALIDATION 
        InitUseSuppliedCreds        = 0x00000080,   // ISC_REQ_USE_SUPPLIED_CREDS
        InitIdentify                = 0x00020000,   // ISC_REQ_IDENTIFY
        AcceptIdentify              = 0x00080000,   // ASC_REQ_IDENTIFY
 
        InitHttp                    = 0x10000000,   // ISC_REQ_HTTP
        AcceptHttp                  = 0x10000000,   // ASC_REQ_HTTP 
    } 

    internal class NTAuthentication { 

        static private int s_UniqueGroupId = 1;
        static private ContextCallback s_InitializeCallback = new ContextCallback(InitializeCallback);
 
        private bool m_IsServer;
 
        private SafeFreeCredentials m_CredentialsHandle; 
        private SafeDeleteContext   m_SecurityContext;
        private string m_Spn; 

        private int m_TokenSize;
        private ContextFlags m_RequestedContextFlags;
        private ContextFlags m_ContextFlags; 
        private string m_UniqueUserId;
 
        private bool m_IsCompleted; 
        private string m_ProtocolName;
        private SecSizes m_Sizes; 
        private string m_LastProtocolName;
        private string m_Package;

        // 
        // Properties
        // 
        internal string UniqueUserId { 
            get {
                return m_UniqueUserId; 
            }
        }

        // The semantic of this propoerty is "Don't call me again". 
        // It can be completed either with success or error
        // The latest case is signalled by IsValidContext==false 
        internal bool IsCompleted { 
            get {
                return m_IsCompleted; 
            }
        }

        internal bool IsValidContext { 
            get {
                return !(m_SecurityContext == null || m_SecurityContext.IsInvalid); 
            } 
        }
 
        internal string AssociatedName {
            get {
                if (!(IsValidContext && IsCompleted))
                    throw new Win32Exception((int)SecurityStatus.InvalidHandle); 

                string name = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.Names) as string; 
                GlobalLog.Print("NTAuthentication: The context is associated with [" + name + "]"); 
                return name;
            } 
        }

        internal bool IsConfidentialityFlag {
            get { 
                return (m_ContextFlags & ContextFlags.Confidentiality) != 0;
            } 
        } 

        internal bool IsIntegrityFlag { 
            get {
                return (m_ContextFlags & (m_IsServer?ContextFlags.AcceptIntegrity:ContextFlags.InitIntegrity)) != 0;
            }
        } 

        internal bool IsMutualAuthFlag { 
            get { 
                return (m_ContextFlags & ContextFlags.MutualAuth) != 0;
            } 
        }

        internal bool IsDelegationFlag {
            get { 
                return (m_ContextFlags & ContextFlags.Delegate) != 0;
            } 
        } 

        internal bool IsIdentifyFlag { 
            get {
                return (m_ContextFlags & (m_IsServer?ContextFlags.AcceptIdentify:ContextFlags.InitIdentify)) != 0;
            }
        } 

        internal string Spn { 
            get { 
                return m_Spn;
            } 
        }

        //
        // True indicates this instance is for Server and will use AcceptSecurityContext SSPI API 
        //
        internal bool IsServer { 
            get { 
                return m_IsServer;
            } 
        }

        //
        internal bool IsKerberos 
        {
            get { 
                if (m_LastProtocolName  == null) 
                    m_LastProtocolName = ProtocolName;
 
                return (object) m_LastProtocolName == (object) NegotiationInfoClass.Kerberos;
            }
        }
        internal bool IsNTLM 
        {
            get { 
                if (m_LastProtocolName  == null) 
                    m_LastProtocolName = ProtocolName;
 
                return (object) m_LastProtocolName == (object) NegotiationInfoClass.NTLM;
            }
        }
 
        internal string Package
        { 
            get 
            {
                return m_Package; 
            }
        }

        internal string ProtocolName { 
            get {
                // NB: May return string.Empty if the auth is not done yet or failed 
                if (m_ProtocolName==null) 
                {
                    NegotiationInfoClass negotiationInfo = null; 

                    if (IsValidContext)
                    {
                        negotiationInfo = SSPIWrapper.QueryContextAttributes(GlobalSSPI.SSPIAuth, m_SecurityContext, ContextAttribute.NegotiationInfo) as NegotiationInfoClass; 
                        if (IsCompleted) {
                            if (negotiationInfo == null) 
                            { 
                                // Win9x workaround for not supported query NegotiateInfo context attribute
                                if(ComNetOS.IsWin9x) 
                                {
                                    m_ProtocolName = NegotiationInfoClass.NTLM;
                                    return m_ProtocolName;
                                } 
                            }
                            else 
                            { 
                                //cache it only when it's completed
                                m_ProtocolName = negotiationInfo.AuthenticationPackage; 
                            }
                        }
                    }
                    return negotiationInfo == null? string.Empty: negotiationInfo.AuthenticationPackage; 
                }
                return m_ProtocolName; 
            } 
        }
 
        internal SecSizes Sizes {
            get {
                GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::MaxDataSize|The context is not completed or invalid.", ValidationHelper.HashString(this));
                if (m_Sizes == null) { 
                    m_Sizes = SSPIWrapper.QueryContextAttributes(
                                  GlobalSSPI.SSPIAuth, 
                                  m_SecurityContext, 
                                  ContextAttribute.Sizes
                                  ) as SecSizes; 
                }
                return m_Sizes;
            }
        } 

        // 
        // .Ctors 
        //
 
        //
        // Use only for client HTTP authentication
        //
        internal NTAuthentication(string package, NetworkCredential networkCredential, string spn, WebRequest request) : 
            this(false, package, networkCredential, spn, GetHttpContextFlags(request), request.GetWritingContext())
        { 
            // 
            //  In order to prevent a race condition where one request could
            //  steal a connection from another request, before a handshake is 
            //  complete, we create a new Group for each authentication request.
            //
            if (package == NtlmClient.AuthType || package == NegotiateClient.AuthType) {
                m_UniqueUserId = (Interlocked.Increment(ref s_UniqueGroupId)).ToString(NumberFormatInfo.InvariantInfo) + m_UniqueUserId; 
            }
        } 
        // 
        private static ContextFlags GetHttpContextFlags(WebRequest request)
        { 
            ContextFlags contextFlags = ContextFlags.Connection | ContextFlags.Confidentiality | ContextFlags.ReplayDetect | ContextFlags.SequenceDetect;

            if (request.ImpersonationLevel == TokenImpersonationLevel.Anonymous)
                throw new NotSupportedException(SR.GetString(SR.net_auth_no_anonymous_support)); 
            else if(request.ImpersonationLevel == TokenImpersonationLevel.Identification)
                contextFlags |= ContextFlags.InitIdentify; 
            else if(request.ImpersonationLevel == TokenImpersonationLevel.Delegation) 
                contextFlags |= ContextFlags.Delegate;
 
            if (request.AuthenticationLevel == AuthenticationLevel.MutualAuthRequested || request.AuthenticationLevel == AuthenticationLevel.MutualAuthRequired)
                contextFlags |= ContextFlags.MutualAuth;

            return contextFlags; 
        }
 
        // 
        // This constructor is for a general (non-HTTP) authentication handshake using SSPI
        // Works for both client and server sides. 
        //
        // Security: we may need to impersonate on user behalf as to temporarily restore original thread token.
        [SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
        internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ContextAwareResult context) 
        {
            // 
            // check if we're using DefaultCredentials 
            //
            if (credential is SystemNetworkCredential && ComNetOS.IsWinNt) 
            {
                //
#if DEBUG
                GlobalLog.Assert(context == null || context.IdentityRequested, "NTAuthentication#{0}::.ctor|Authentication required when it wasn't expected.  (Maybe Credentials was changed on another thread?)", ValidationHelper.HashString(this)); 
#endif
 
                WindowsIdentity w = context == null ? null : context.Identity; 
                try
                { 
                    IDisposable ctx = w == null ? null : w.Impersonate();
                    if (ctx != null)
                    {
                        using (ctx) 
                        {
                            Initialize(isServer, package, credential, spn, requestedContextFlags); 
                        } 
                    }
                    else 
                    {
                        ExecutionContext x = context == null ? null : context.ContextCopy;
                        if (x == null)
                        { 
                            Initialize(isServer, package, credential, spn, requestedContextFlags);
                        } 
                        else 
                        {
                            ExecutionContext.Run(x, s_InitializeCallback, new InitializeCallbackContext(this, isServer, package, credential, spn, requestedContextFlags)); 
                        }
                    }
                }
                catch 
                {
                    // Prevent the impersonation from leaking to upstack exception filters. 
                    throw; 
                }
            } 
            else
            {
                Initialize(isServer, package, credential, spn, requestedContextFlags);
            } 
        }
 
        // 
        // This overload does not attmept to impersonate because the caller either did it already or the original thread context is still preserved
        // 
        internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags) {
            Initialize(isServer, package, credential, spn, requestedContextFlags);
        }
 
        //
        // This overload always uses the default credentials for the process. 
        // 
        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
        internal NTAuthentication(bool isServer, string package, string spn, ContextFlags requestedContextFlags) 
        {
            try
            {
                using (WindowsIdentity.Impersonate(IntPtr.Zero)) 
                {
                    Initialize(isServer, package, SystemNetworkCredential.defaultCredential, spn, requestedContextFlags); 
                } 
            }
            catch 
            {
                // Avoid exception filter attacks.
                throw;
            } 
        }
 
        private class InitializeCallbackContext 
        {
            internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags) 
            {
                this.thisPtr = thisPtr;
                this.isServer = isServer;
                this.package = package; 
                this.credential = credential;
                this.spn = spn; 
                this.requestedContextFlags = requestedContextFlags; 
            }
 
            internal readonly NTAuthentication thisPtr;
            internal readonly bool isServer;
            internal readonly string package;
            internal readonly NetworkCredential credential; 
            internal readonly string spn;
            internal readonly ContextFlags requestedContextFlags; 
        } 

        private static void InitializeCallback(object state) 
        {
            InitializeCallbackContext context = (InitializeCallbackContext)state;
            context.thisPtr.Initialize(context.isServer, context.package, context.credential, context.spn, context.requestedContextFlags);
        } 

        // 
        private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags) { 
            GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor() package:" + ValidationHelper.ToString(package) + " spn:" + ValidationHelper.ToString(spn) + " flags :" + requestedContextFlags.ToString());
            m_TokenSize = SSPIWrapper.GetVerifyPackageInfo(GlobalSSPI.SSPIAuth, package, true).MaxToken; 
            m_IsServer = isServer;
            m_Spn = spn;
            m_SecurityContext = null;
            m_RequestedContextFlags = requestedContextFlags; 
            m_Package = package;
 
            GlobalLog.Print("Peer SPN-> '" + m_Spn + "'"); 
            //
            // check if we're using DefaultCredentials 
            //
            if (credential is SystemNetworkCredential)
            {
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using DefaultCredentials"); 
                m_CredentialsHandle = SSPIWrapper.AcquireDefaultCredential(
                                                    GlobalSSPI.SSPIAuth, 
                                                    package, 
                                                    (m_IsServer? CredentialUse.Inbound: CredentialUse.Outbound));
                m_UniqueUserId = "/S"; // save off for unique connection marking ONLY used by HTTP client 
            }
            else
            {
 
                //
                // we're not using DefaultCredentials, we need a 
                // AuthIdentity struct to contain credentials 
                // SECREVIEW:
                // we'll save username/domain in temp strings, to avoid decrypting multiple times. 
                // password is only used once
                //
                string username = credential.InternalGetUserName();
 
                string domain = credential.InternalGetDomain();
                // ATTN: 
                // NetworkCredential class does not differentiate between null and "" but SSPI packages treat these cases differently 
                // For NTLM we want to keep "" for Wdigest.Dll we should use null.
                AuthIdentity authIdentity = new AuthIdentity(username, credential.InternalGetPassword(), (object)package == (object)NegotiationInfoClass.WDigest && (domain == null || domain.Length == 0)? null: domain); 

                m_UniqueUserId = domain + "/" + username + "/U"; // save off for unique connection marking ONLY used by HTTP client

                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using authIdentity:" + authIdentity.ToString()); 

                m_CredentialsHandle = SSPIWrapper.AcquireCredentialsHandle( 
                                                    GlobalSSPI.SSPIAuth, 
                                                    package,
                                                    (m_IsServer? CredentialUse.Inbound: CredentialUse.Outbound), 
                                                    ref authIdentity
                                                    );
            }
        } 

        // 
        // Methods 
        //
 

        // This will return an client token when conducted authentication on server side'
        // This token can be used ofr impersanation
        // We use it to create a WindowsIdentity and hand it out to the server app. 
        internal SafeCloseHandle GetContextToken(out SecurityStatus status)
        { 
            GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", ValidationHelper.HashString(this)); 
            GlobalLog.Assert(IsServer, "NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", ValidationHelper.HashString(this));
 
            if (!IsValidContext) {
                throw new Win32Exception((int)SecurityStatus.InvalidHandle);
            }
 

            SafeCloseHandle token = null; 
            status = (SecurityStatus) SSPIWrapper.QuerySecurityContextToken( 
                GlobalSSPI.SSPIAuth,
                m_SecurityContext, 
                out token);

            return token;
        } 

        internal SafeCloseHandle GetContextToken() 
        { 
            SecurityStatus status;
            SafeCloseHandle token = GetContextToken(out status); 
            if (status != SecurityStatus.OK) {
                throw new Win32Exception((int)status);
            }
            return token; 
        }
 
        internal void CloseContext() 
        {
            if (m_SecurityContext != null && !m_SecurityContext.IsClosed) 
                m_SecurityContext.Close();
        }

 
        //
        // NTAuth::GetOutgoingBlob() 
        // Created:   12-01-1999: L.M. 
        // Description:
        // Accepts a base64 encoded incoming security blob and returns 
        // a base 64 encoded outgoing security blob
        //
        // This method is for HttpWebRequest usage only as it has semantic bound to it
        internal string GetOutgoingBlob(string incomingBlob) { 
            GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", incomingBlob);
            byte[] decodedIncomingBlob = null; 
            if (incomingBlob != null && incomingBlob.Length > 0) { 
                decodedIncomingBlob = Convert.FromBase64String(incomingBlob);
            } 
            byte[] decodedOutgoingBlob = null;

            if ((IsValidContext || IsCompleted) && decodedIncomingBlob == null) {
                // we tried auth previously, now we got a null blob, we're done. this happens 
                // with Kerberos & valid credentials on the domain but no ACLs on the resource
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() null blob AND m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:[0x" + m_SecurityContext.ToString() + "]"); 
                m_IsCompleted = true; 
            }
            else { 
                SecurityStatus statusCode;
#if TRAVE
                try {
#endif 
                    decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, true, out statusCode);
#if TRAVE 
                } catch (Exception exception) { 
                    if (NclUtilities.IsFatal(exception)) throw;
 
                    GlobalLog.LeaveException("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", exception);
                    throw;
                }
#endif 
            }
 
            string outgoingBlob = null; 
            if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) {
                outgoingBlob = Convert.ToBase64String(decodedOutgoingBlob); 
            }

            //This is only for HttpWebRequest that does not need security context anymore
            if (IsCompleted) 
            {
                string name = ProtocolName; // cache the only info needed from a completed context before closing it 
                CloseContext(); 
            }
            GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", outgoingBlob); 
            return outgoingBlob;
        }

        // NTAuth::GetOutgoingBlob() 
        // Created:   12-01-1999: L.M.
        // Description: 
        // Accepts an incoming binary security blob  and returns 
        // an outgoing binary security blob
        internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode) 
        {
            GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes");

            SecurityBuffer inSecurityBuffer = null; 
            if (incomingBlob != null) {
//                GlobalLog.Print("in blob = "); 
//                GlobalLog.Dump(incomingBlob); 
                inSecurityBuffer = new SecurityBuffer(incomingBlob,BufferType.Token);
            } 

            SecurityBuffer outSecurityBuffer = new SecurityBuffer(m_TokenSize, BufferType.Token);

            bool firstTime = m_SecurityContext == null; 
            try {
                if (!m_IsServer) { 
                    // client session 
                    statusCode = (SecurityStatus) SSPIWrapper.InitializeSecurityContext(
                        GlobalSSPI.SSPIAuth, 
                        ref m_CredentialsHandle,
                        ref m_SecurityContext,
                        m_Spn,
                        m_RequestedContextFlags, 
                        Endianness.Network,
                        inSecurityBuffer, 
                        outSecurityBuffer, 
                        ref m_ContextFlags );
 
                    GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");

                    if (statusCode == SecurityStatus.CompleteNeeded)
                    { 
                        SecurityBuffer[] inSecurityBuffers = new SecurityBuffer[1];
                        inSecurityBuffers[0] = outSecurityBuffer; 
 
                        statusCode = (SecurityStatus) SSPIWrapper.CompleteAuthToken(
                            GlobalSSPI.SSPIAuth, 
                            ref m_SecurityContext,
                            inSecurityBuffers );

                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); 
                        outSecurityBuffer.token = null;
                    } 
                } 
                else {
                    // server session 
                    statusCode = (SecurityStatus) SSPIWrapper.AcceptSecurityContext(
                        GlobalSSPI.SSPIAuth,
                        ref m_CredentialsHandle,
                        ref m_SecurityContext, 
                        m_RequestedContextFlags,
                        Endianness.Network, 
                        inSecurityBuffer, 
                        outSecurityBuffer,
                        ref m_ContextFlags ); 

                    GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                }
            } 
            finally {
                // 
                // Assuming the ISC or ASC has referenced the credential on the first successful call, 
                // we want to decrement the effective ref count by "disposing" it.
                // The real dispose will happen when the security context is closed. 
                // Note if the first call was not successfull the handle is physically destroyed here
                //
              if (firstTime && m_CredentialsHandle != null)
                  m_CredentialsHandle.Close(); 
            }
 
 
          if (((int) statusCode & unchecked((int) 0x80000000)) != 0)
          { 
                CloseContext();
                m_IsCompleted = true;
                if (throwOnError) {
                    Win32Exception exception = new Win32Exception((int) statusCode); 
                    GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception);
                    throw exception; 
                } 
                GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                return null; 
            }
            else if (firstTime && m_CredentialsHandle != null)
            {
                // cache until it is pushed out by newly incoming handles 
                SSPIHandleCache.CacheCredential(m_CredentialsHandle);
            } 
 
            // the return value from SSPI will tell us correctly if the
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm 
            // we also have to consider the case in which SSPI formed a new context, in this case we're done as well.
            if (statusCode == SecurityStatus.OK)
            {
                // we're sucessfully done 
                GlobalLog.Assert(statusCode == SecurityStatus.OK, "NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", ValidationHelper.HashString(this), (int)statusCode, statusCode, ValidationHelper.HashString(m_SecurityContext), ValidationHelper.ToString(m_SecurityContext));
                m_IsCompleted = true; 
            } 
            else {
                // we need to continue 
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:" + ValidationHelper.ToString(m_SecurityContext) + "]");
            }
//            GlobalLog.Print("out token = " + outSecurityBuffer.ToString());
//            GlobalLog.Dump(outSecurityBuffer.token); 
            GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString());
            return outSecurityBuffer.token; 
        } 

        // for Server side (IIS 6.0) see: \\netindex\Sources\inetsrv\iis\iisrearc\iisplus\ulw3\digestprovider.cxx 
        // for Client side (HTTP.SYS) see: \\netindex\Sources\net\http\sys\ucauth.c
        internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode)
        {
            GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", incomingBlob); 

            m_RequestedContextFlags |= (ContextFlags.AcceptHttp | ContextFlags.ReplayDetect | ContextFlags.SequenceDetect); 
 
            // second time call with 3 incoming buffers to select HTTP client.
            // we should get back a SecurityStatus.OK and a non null outgoingBlob. 
            SecurityBuffer[] inSecurityBuffers = null;
            SecurityBuffer outSecurityBuffer = new SecurityBuffer(m_TokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token);

            bool firstTime = m_SecurityContext == null; 
            try {
                if (!m_IsServer) { 
                    // client session 

                    if (!isClientPreAuth) { 
                        // make sure we don't require this flag or we'd drop qop="auth"
                        m_RequestedContextFlags &= ~ContextFlags.Confidentiality;

                        if (incomingBlob!=null) { 
                            inSecurityBuffers = new SecurityBuffer[] {
                                new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), BufferType.Token), 
                                new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), 
                                new SecurityBuffer(null, BufferType.Parameters),
                            }; 
                        }

                        statusCode = (SecurityStatus) SSPIWrapper.InitializeSecurityContext(
                            GlobalSSPI.SSPIAuth, 
                            m_CredentialsHandle,
                            ref m_SecurityContext, 
                            m_Spn, // this must match the Uri in the HTTP status line for the current request 
                            m_RequestedContextFlags,
                            Endianness.Network, 
                            inSecurityBuffers,
                            outSecurityBuffer,
                            ref m_ContextFlags );
 
                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                    } 
                    else { 
#if WDIGEST_PREAUTH
                        inSecurityBuffers = new SecurityBuffer[] { 
                            new SecurityBuffer(null, BufferType.Token),
                            new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters),
                            new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters),
                            new SecurityBuffer(null, BufferType.Parameters), 
                            outSecurityBuffer,
                        }; 
 
                        statusCode = (SecurityStatus) SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, inSecurityBuffers, 0);
 
                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.MakeSignature() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
#else
                        statusCode = SecurityStatus.OK;
                        GlobalLog.Assert("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob()", "Invalid code path."); 
#endif
                    } 
                } 
                else {
                    // server session 

                    inSecurityBuffers = new SecurityBuffer[] {
                        incomingBlob==null ? null : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(incomingBlob), BufferType.Token),
                        requestMethod==null ? null : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters), 
                        requestedUri==null ? null : new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters),
                        null, // BufferType.Parameters 
                        realm==null ? null : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters), 
                    };
 
                    statusCode = (SecurityStatus) SSPIWrapper.AcceptSecurityContext(
                        GlobalSSPI.SSPIAuth,
                        m_CredentialsHandle,
                        ref m_SecurityContext, 
                        m_RequestedContextFlags,
                        Endianness.Network, 
                        inSecurityBuffers, 
                        outSecurityBuffer,
                        ref m_ContextFlags ); 

                    GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");

                    if (statusCode == SecurityStatus.CompleteNeeded) 
                    {
                        inSecurityBuffers[4] = outSecurityBuffer; 
 
                        statusCode = (SecurityStatus) SSPIWrapper.CompleteAuthToken(
                                GlobalSSPI.SSPIAuth, 
                                ref m_SecurityContext,
                                inSecurityBuffers );

                        GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); 

                        outSecurityBuffer.token = null; 
                    } 
                }
            } 
            finally {
                //
                // Assuming the ISC or ASC has referenced the credential on the first successful call,
                // we want to decrement the effective ref count by "disposing" it. 
                // The real dispose will happen when the security context is closed.
                // Note if the first call was not successfull the handle is physically destroyed here 
                // 
              if (firstTime && m_CredentialsHandle != null)
                  m_CredentialsHandle.Close(); 
            }


            if (((int) statusCode & unchecked((int) 0x80000000)) != 0) 
            {
                CloseContext(); 
                if (throwOnError) { 
                    Win32Exception exception = new Win32Exception((int) statusCode);
                    GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "Win32Exception:" + exception); 
                    throw exception;
                }
                GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "null statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
                return null; 
            }
            else if (firstTime && m_CredentialsHandle != null) 
            { 
                // cache until it is pushed out by newly incoming handles
                SSPIHandleCache.CacheCredential(m_CredentialsHandle); 
            }


            // the return value from SSPI will tell us correctly if the 
            // handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
            if (statusCode == SecurityStatus.OK) 
            { 
                // we're done, cleanup
                m_IsCompleted = true; 
            }
            else {
                // we need to continue
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() need continue statusCode:[0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(m_SecurityContext) + "::Handle:" + ValidationHelper.ToString(m_SecurityContext) + "]"); 
            }
            GlobalLog.Print("out token = " + outSecurityBuffer.ToString()); 
            GlobalLog.Dump(outSecurityBuffer.token); 
            GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() IsCompleted:" + IsCompleted.ToString());
 
            byte[] decodedOutgoingBlob = outSecurityBuffer.token;
            string outgoingBlob = null;
            if (decodedOutgoingBlob!=null && decodedOutgoingBlob.Length>0) {
                outgoingBlob = WebHeaderCollection.HeaderEncoding.GetString(decodedOutgoingBlob, 0, outSecurityBuffer.size); 
            }
            GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", outgoingBlob); 
            return outgoingBlob; 
        }
 
        internal int Encrypt(byte[] buffer, int offset, int count, ref byte[] output, uint sequenceNumber) {
            SecSizes sizes = Sizes;

            try 
            {
                int maxCount = checked(Int32.MaxValue - 4 - sizes.BlockSize - sizes.SecurityTrailer); 
 
                if (count > maxCount || count < 0)
                { 
                    throw new ArgumentOutOfRangeException("count", SR.GetString(SR.net_io_out_range, maxCount));
                }
            }
            catch(Exception e) 
            {
                if (!NclUtilities.IsFatal(e)){ 
                    GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::Encrypt", "Arguments out of range."); 
                }
                throw; 
            }

            int resultSize = count + sizes.SecurityTrailer + sizes.BlockSize;
            if (output == null || output.Length < resultSize+4) 
            {
                output = new byte[resultSize+4]; 
            } 

            // make a copy of user data for in-place encryption 
            Buffer.BlockCopy(buffer, offset, output, 4 + sizes.SecurityTrailer, count);

            // prepare buffers TOKEN(signautre), DATA and Padding
            SecurityBuffer[] securityBuffer = new SecurityBuffer[3]; 
            securityBuffer[0] = new SecurityBuffer(output, 4, sizes.SecurityTrailer, BufferType.Token);
            securityBuffer[1] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer, count, BufferType.Data); 
            securityBuffer[2] = new SecurityBuffer(output, 4 + sizes.SecurityTrailer + count, sizes.BlockSize, BufferType.Padding); 

            int errorCode; 
            if (IsConfidentialityFlag)
            {
                errorCode = SSPIWrapper.EncryptMessage(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, sequenceNumber);
            } 
            else
            { 
                if (IsNTLM) 
                    securityBuffer[1].type |= BufferType.ReadOnlyFlag;
                errorCode = SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, 0); 
            }


            if (errorCode != 0) { 
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::Encrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode); 
            } 

            // Compacting the result... 
            resultSize = securityBuffer[0].size;
            bool forceCopy = false;
            if (resultSize != sizes.SecurityTrailer)
            { 
                forceCopy = true;
                Buffer.BlockCopy(output, securityBuffer[1].offset, output, 4 + resultSize, securityBuffer[1].size); 
            } 

            resultSize += securityBuffer[1].size; 
            if (securityBuffer[2].size != 0 && (forceCopy || resultSize != (count + sizes.SecurityTrailer)))
                Buffer.BlockCopy(output, securityBuffer[2].offset, output, 4 + resultSize, securityBuffer[2].size);

            resultSize += securityBuffer[2].size; 

            unchecked { 
                output[0] = (byte)((resultSize) & 0xFF); 
                output[1] = (byte)(((resultSize)>>8) & 0xFF);
                output[2] = (byte)(((resultSize)>>16) & 0xFF); 
                output[3] = (byte)(((resultSize)>>24) & 0xFF);
            }
            return resultSize+4;
        } 

        internal int Decrypt(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) 
        { 
            if (offset < 0 || offset > (payload == null ? 0 : payload.Length))
            { 
                GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt", "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset");
            }
            if (count < 0 || count > (payload == null ? 0 : payload.Length - offset)) 
            {
                GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt", "Argument 'count' out of range."); 
                throw new ArgumentOutOfRangeException("count"); 
            }
 
            if (IsNTLM)
                return DecryptNtlm(payload, offset, count, out newOffset, expectedSeqNumber);

            // 
            // Kerberos and up
            // 
 
            SecurityBuffer[] securityBuffer = new SecurityBuffer[2];
            securityBuffer[0] = new SecurityBuffer(payload, offset, count, BufferType.Stream); 
            securityBuffer[1] = new SecurityBuffer(0, BufferType.Data);

            int errorCode;
            if (IsConfidentialityFlag) 
            {
                errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber); 
            } 
            else
            { 
                errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber);
            }

            if (errorCode != 0) 
            {
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo)); 
                throw new Win32Exception(errorCode); 
            }
 
            if (securityBuffer[1].type != BufferType.Data)
                throw new InternalException();

            newOffset = securityBuffer[1].offset; 
            return securityBuffer[1].size;
 
        } 
        //
        private int DecryptNtlm(byte[] payload, int offset, int count, out int newOffset, uint expectedSeqNumber) 
        {
            // For the most part the arguments are verified in Encrypt().
            if (count < 16)
            { 
                GlobalLog.Assert(false, "NTAuthentication#" + ValidationHelper.HashString(this) + "::DecryptNtlm", "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count"); 
            } 

            SecurityBuffer[] securityBuffer = new SecurityBuffer[2]; 
            securityBuffer[0] = new SecurityBuffer(payload, offset, 16, BufferType.Token);
            securityBuffer[1] = new SecurityBuffer(payload, offset + 16, count-16, BufferType.Data);

            int errorCode; 
            BufferType realDataType = BufferType.Data;
 
            if (IsConfidentialityFlag) 
            {
                errorCode = SSPIWrapper.DecryptMessage(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber); 
            }
            else
            {
                realDataType |= BufferType.ReadOnlyFlag; 
                securityBuffer[1].type = realDataType;
                errorCode = SSPIWrapper.VerifySignature(GlobalSSPI.SSPIAuth, m_SecurityContext, securityBuffer, expectedSeqNumber); 
            } 

            if (errorCode != 0) 
            {
                GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::Decrypt() throw Error = " + errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode);
            } 

            if (securityBuffer[1].type != realDataType) 
                throw new InternalException(); 

            newOffset = securityBuffer[1].offset; 
            return securityBuffer[1].size;
        }

        // 
        // VerifySignature
        // 
        // Adapted from Decrypt method above as a more generic message 
        // signature verify method for SMTP AUTH GSSAPI (SASL).
        // Decrypt method, used NegotiateStream, couldn't be used due 
        // to special cases for NTLM.
        //
        // See SmtpNegotiateAuthenticationModule class for caller.
        // 
        internal int VerifySignature(byte[] buffer, int offset, int count) {
 
            // validate offset within length 
            if (offset < 0 || offset > (buffer == null ? 0 : buffer.Length)) {
                GlobalLog.Assert( 
                            false,
                            "NTAuthentication#" +
                            ValidationHelper.HashString(this) +
                            "::VerifySignature", 
                            "Argument 'offset' out of range.");
                throw new ArgumentOutOfRangeException("offset"); 
            } 

            // validate count within offset and end of buffer 
            if (count < 0 ||
                count > (buffer == null ? 0 : buffer.Length - offset)) {
                GlobalLog.Assert(
                            false, 
                            "NTAuthentication#" +
                            ValidationHelper.HashString(this) + 
                            "::VerifySignature", 
                            "Argument 'count' out of range.");
                throw new ArgumentOutOfRangeException("count"); 
            }

            // setup security buffers for ssp call
            // one points at signed data 
            // two will receive payload if signature is valid
            SecurityBuffer[] securityBuffer = new SecurityBuffer[2]; 
            securityBuffer[0] = 
                new SecurityBuffer(buffer, offset, count, BufferType.Stream);
            securityBuffer[1] = new SecurityBuffer(0, BufferType.Data); 

            // call SSP function
            int errorCode = SSPIWrapper.VerifySignature(
                                GlobalSSPI.SSPIAuth, 
                                m_SecurityContext,
                                securityBuffer, 
                                0); 

            // throw if error 
            if (errorCode != 0)
            {
                GlobalLog.Print(
                            "NTAuthentication#" + 
                            ValidationHelper.HashString(this) +
                            "::VerifySignature() threw Error = " + 
                            errorCode.ToString("x", 
                                NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode); 
            }

            // not sure why this is here - retained from Encrypt code above
            if (securityBuffer[1].type != BufferType.Data) 
                throw new InternalException();
 
            // return validated payload size 
            return securityBuffer[1].size;
        } 

        //
        // MakeSignature
        // 
        // Adapted from Encrypt method above as a more generic message
        // signing method for SMTP AUTH GSSAPI (SASL). 
        // Encrypt method, used for NegotiateStream, put size at head of 
        // message.  Don't need that
        // 
        // See SmtpNegotiateAuthenticationModule class for caller.
        //
        internal int MakeSignature(
                        byte[] buffer, 
                        int offset,
                        int count, 
                        ref byte[] output) { 
            SecSizes sizes = Sizes;
 

            // alloc new output buffer if not supplied or too small
            int resultSize = count + sizes.MaxSignature;
            if (output == null || output.Length < resultSize) 
            {
                output = new byte[resultSize]; 
            } 

            // make a copy of user data for in-place encryption 
            Buffer.BlockCopy(buffer, offset, output, sizes.MaxSignature, count);

            // setup security buffers for ssp call
            SecurityBuffer[] securityBuffer = new SecurityBuffer[2]; 
            securityBuffer[0] = new SecurityBuffer(output, 0, sizes.MaxSignature, BufferType.Token);
            securityBuffer[1] = new SecurityBuffer(output, sizes.MaxSignature, count, BufferType.Data); 
 
            // call SSP Function
            int errorCode = SSPIWrapper.MakeSignature( 
                                GlobalSSPI.SSPIAuth,
                                m_SecurityContext,
                                securityBuffer,
                                0); 

            // throw if error 
            if (errorCode != 0) { 
                GlobalLog.Print(
                    "NTAuthentication#" + 
                    ValidationHelper.HashString(this) +
                    "::Encrypt() throw Error = " +
                    errorCode.ToString("x", NumberFormatInfo.InvariantInfo));
                throw new Win32Exception(errorCode); 
            }
 
            // return signed size 
            return securityBuffer[0].size + securityBuffer[1].size;
        } 
    }

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
    internal struct AuthIdentity { 
        // see SEC_WINNT_AUTH_IDENTITY_W
        internal string UserName; 
        internal int UserNameLength; 
        internal string Domain;
        internal int DomainLength; 
        internal string Password;
        internal int PasswordLength;
        internal int Flags;
 
        internal AuthIdentity(string userName, string password, string domain) {
            UserName = userName; 
            UserNameLength = userName==null ? 0 : userName.Length; 
            Password = password;
            PasswordLength = password==null ? 0 : password.Length; 
            Domain = domain;
            DomainLength = domain==null ? 0 : domain.Length;
            // Flags are 2 for Unicode and 1 for ANSI. We use 2 on NT and 1 on Win9x.
            Flags = ComNetOS.IsWin9x? 1: 2; 
        }
        public override string ToString() { 
            return ValidationHelper.ToString(Domain) + "\\" + ValidationHelper.ToString(UserName); 
        }
    } 

}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK