示例#1
0
        internal static SecurityStatusPal InitializeSecurityContext(
            ref SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext?securityContext,
            string?spn,
            ContextFlagsPal requestedContextFlags,
            ReadOnlySpan <byte> incomingBlob,
            ChannelBinding?channelBinding,
            ref byte[]?resultBlob,
            out int resultBlobLength,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                channelBinding,
                spn,
                requestedContextFlags,
                incomingBlob,
                out resultBlob,
                ref contextFlags);

            resultBlobLength = resultBlob?.Length ?? 0;

            return(status);
        }
示例#2
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string spn,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            // TODO (Issue #3718): The second buffer can contain a channel binding which is not supported
            if ((null != inSecurityBufferArray) && (inSecurityBufferArray.Length > 1))
            {
                throw new PlatformNotSupportedException(SR.net_nego_channel_binding_not_supported);
            }

            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            return(EstablishSecurityContext(
                       negoCredentialsHandle,
                       ref securityContext,
                       spn,
                       requestedContextFlags,
                       ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
                       outSecurityBuffer,
                       ref contextFlags));
        }
        public SafeDeleteNegoContext(SafeFreeNegoCredentials credential)
            : base(IntPtr.Zero)
        {
            Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext");
            bool added = false;

            credential.DangerousAddRef(ref added);
            _credential = credential;
            _context    = new SafeGssContextHandle();
        }
示例#4
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string[] spns,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            // TODO (Issue #3718): The second buffer can contain a channel binding which is not supported
            if ((null != inSecurityBufferArray) && (inSecurityBufferArray.Length > 1))
            {
                throw new PlatformNotSupportedException(Strings.net_nego_channel_binding_not_supported);
            }

            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;
            SecurityStatusPal       status = default;

            foreach (string spn in spns)
            {
                if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
                {
                    throw new PlatformNotSupportedException(Strings.net_nego_not_supported_empty_target_with_defaultcreds);
                }

                status = EstablishSecurityContext(
                    negoCredentialsHandle,
                    ref securityContext,
                    spn,
                    requestedContextFlags,
                    ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
                    outSecurityBuffer,
                    ref contextFlags);

                if (status.ErrorCode != SecurityStatusPalErrorCode.InternalError)
                {
                    break; // Successful case, exit the loop with current SPN.
                }
                else
                {
                    securityContext = null; // Reset security context to be generated again for next SPN.
                }
            }

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(Strings.net_nego_protection_level_not_supported);
                }
            }
            return(status);
        }
示例#5
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
     : this(credential)
 {
     try
     {
         _targetName = SafeGssNameHandle.CreateTarget(targetName);
     }
     catch
     {
         Dispose();
         throw;
     }
 }
示例#6
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
     : base(credential)
 {
     Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext");
     try
     {
         _targetName = SafeGssNameHandle.CreatePrincipal(targetName);
     }
     catch
     {
         Dispose();
         throw;
     }
 }
示例#7
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
     : base(credential)
 {
     Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext");
     try
     {
         _targetName = SafeGssNameHandle.CreatePrincipal(targetName);
     }
     catch
     {
         Dispose();
         throw;
     }
 }
示例#8
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
     : base(credential)
 {
     Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext");
     try
     {
         _targetNameKerberos = SafeGssNameHandle.CreateTarget(targetName, isNtlmTarget: false);
         _targetNameNtlm     = SafeGssNameHandle.CreateTarget(targetName, isNtlmTarget: true);
     }
     catch
     {
         Dispose();
         throw;
     }
 }
示例#9
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
     : this(credential)
 {
     try
     {
         // Convert any "SERVICE/HOST" style of targetName to use "SERVICE@HOST" style.
         // This is because the System.Net.Security.Native GSS-API layer uses
         // GSS_C_NT_HOSTBASED_SERVICE format for targetName.
         _targetName = SafeGssNameHandle.CreateTarget(targetName.Replace('/', '@'));
     }
     catch
     {
         Dispose();
         throw;
     }
 }
示例#10
0
        internal static SecurityStatusPal InitializeSecurityContext(
            SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext securityContext,
            string spn,
            ContextFlagsPal requestedContextFlags,
            SecurityBuffer[] inSecurityBufferArray,
            SecurityBuffer outSecurityBuffer,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityBuffer cbtBuffer = null;

            if ((inSecurityBufferArray != null) && (inSecurityBufferArray.Length > 1))
            {
                Debug.Assert(inSecurityBufferArray[1].type == SecurityBufferType.SECBUFFER_CHANNEL_BINDINGS);
                cbtBuffer = inSecurityBufferArray[1];
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                cbtBuffer,
                spn,
                requestedContextFlags,
                ((inSecurityBufferArray != null && inSecurityBufferArray.Length != 0) ? inSecurityBufferArray[0] : null),
                outSecurityBuffer,
                ref contextFlags);

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported);
                }
            }

            return(status);
        }
示例#11
0
        public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
            : base(IntPtr.Zero)
        {
            try
            {
                _targetName = SafeGssNameHandle.CreateTarget(targetName);
                _context    = new SafeGssContextHandle();
            }
            catch
            {
                Dispose();
                throw;
            }
            _credential = credential;
            bool ignore = false;

            _credential.DangerousAddRef(ref ignore);
        }
示例#12
0
        internal static SecurityStatusPal InitializeSecurityContext(
            ref SafeFreeCredentials credentialsHandle,
            ref SafeDeleteContext?securityContext,
            string?spn,
            ContextFlagsPal requestedContextFlags,
            byte[]?incomingBlob,
            ChannelBinding?channelBinding,
            ref byte[]?resultBlob,
            ref ContextFlagsPal contextFlags)
        {
            SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle;

            if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn))
            {
                throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds);
            }

            SecurityStatusPal status = EstablishSecurityContext(
                negoCredentialsHandle,
                ref securityContext,
                channelBinding,
                spn,
                requestedContextFlags,
                incomingBlob,
                ref resultBlob,
                ref contextFlags);

            // Confidentiality flag should not be set if not requested
            if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)
            {
                ContextFlagsPal mask = ContextFlagsPal.Confidentiality;
                if ((requestedContextFlags & mask) != (contextFlags & mask))
                {
                    throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported);
                }
            }

            return(status);
        }
示例#13
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential)
     : base(credential)
 {
     Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext");
     _context = new SafeGssContextHandle();
 }
示例#14
0
        private static SecurityStatusPal EstablishSecurityContext(
          SafeFreeNegoCredentials credential,
          ref SafeDeleteContext context,
          bool isNtlm,
          string targetName,
          ContextFlagsPal inFlags,
          SecurityBuffer inputBuffer,
          SecurityBuffer outputBuffer,
          ref ContextFlagsPal outFlags)
        {
            Debug.Assert(!isNtlm, "EstablishSecurityContext: NTLM is not yet supported");

            if (context == null)
            {
                context = new SafeDeleteNegoContext(credential, targetName);
            }

            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;
            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags);
                uint outputFlags;
                SafeGssContextHandle contextHandle = negoContext.GssContext;
                bool done = Interop.GssApi.EstablishSecurityContext(
                   ref contextHandle,
                   credential.GssCredential,
                   isNtlm,
                   negoContext.TargetName,
                   inputFlags,
                   inputBuffer?.token,
                   out outputBuffer.token,
                   out outputFlags);

                Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
                outputBuffer.size = outputBuffer.token.Length;
                outputBuffer.offset = 0;

                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags);

                // Save the inner context handle for further calls to NetSecurity
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
                if (null == negoContext.GssContext)
                {
                    negoContext.SetGssContext(contextHandle);
                }

                SecurityStatusPalErrorCode errorCode = done ? SecurityStatusPalErrorCode.CompleteNeeded : SecurityStatusPalErrorCode.ContinueNeeded;
                return new SecurityStatusPal(errorCode);
            }
            catch(Exception ex)
            {
                //TODO (Issue #5890): Print exception until issue is fixed
                Debug.Write("Exception Caught. - " + ex);
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("Exception Caught. - " + ex);
                }

                return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex);
            }
        }
示例#15
0
        private static SecurityStatusPal EstablishSecurityContext(
            SafeFreeNegoCredentials credential,
            ref SafeDeleteContext?context,
            ChannelBinding?channelBinding,
            string?targetName,
            ContextFlagsPal inFlags,
            byte[]?incomingBlob,
            ref byte[]?resultBuffer,
            ref ContextFlagsPal outFlags)
        {
            bool isNtlmOnly = credential.IsNtlmOnly;

            if (context == null)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    string protocol = isNtlmOnly ? "NTLM" : "SPNEGO";
                    NetEventSource.Info(context, $"requested protocol = {protocol}, target = {targetName}");
                }

                context = new SafeDeleteNegoContext(credential, targetName !);
            }

            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;

            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags =
                    ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false);
                uint outputFlags;
                bool isNtlmUsed;
                SafeGssContextHandle?contextHandle = negoContext.GssContext;
                bool done = GssInitSecurityContext(
                    ref contextHandle,
                    credential.GssCredential,
                    isNtlmOnly,
                    channelBinding,
                    negoContext.TargetName,
                    inputFlags,
                    incomingBlob,
                    out resultBuffer,
                    out outputFlags,
                    out isNtlmUsed);

                if (done)
                {
                    if (NetEventSource.Log.IsEnabled())
                    {
                        string protocol = isNtlmOnly ? "NTLM" : isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos";
                        NetEventSource.Info(context, $"actual protocol = {protocol}");
                    }

                    // Populate protocol used for authentication
                    negoContext.SetAuthenticationPackage(isNtlmUsed);
                }

                Debug.Assert(resultBuffer != null, "Unexpected null buffer returned by GssApi");
                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(
                    (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false);
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);

                // Save the inner context handle for further calls to NetSecurity
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
                if (null == negoContext.GssContext)
                {
                    negoContext.SetGssContext(contextHandle !);
                }

                SecurityStatusPalErrorCode errorCode = done ?
                                                       (negoContext.IsNtlmUsed && resultBuffer.Length > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
                                                       SecurityStatusPalErrorCode.ContinueNeeded;
                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(null, ex);
                }
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }
示例#16
0
        private static SecurityStatusPal EstablishSecurityContext(
            SafeFreeNegoCredentials credential,
            ref SafeDeleteContext context,
            string targetName,
            ContextFlagsPal inFlags,
            SecurityBuffer inputBuffer,
            SecurityBuffer outputBuffer,
            ref ContextFlagsPal outFlags)
        {
            bool isNtlmOnly = credential.IsNtlmOnly;

            if (context == null)
            {
                // Empty target name causes the failure on Linux, hence passing a non-empty string
                context = isNtlmOnly ? new SafeDeleteNegoContext(credential, credential.UserName) : new SafeDeleteNegoContext(credential, targetName);
            }

            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;

            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false);
                uint outputFlags;
                int  isNtlmUsed;
                SafeGssContextHandle contextHandle = negoContext.GssContext;
                bool done = GssInitSecurityContext(
                    ref contextHandle,
                    credential.GssCredential,
                    isNtlmOnly,
                    negoContext.TargetName,
                    inputFlags,
                    inputBuffer?.token,
                    out outputBuffer.token,
                    out outputFlags,
                    out isNtlmUsed);

                Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
                outputBuffer.size   = outputBuffer.token.Length;
                outputBuffer.offset = 0;
                outFlags            = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false);
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);

                // Save the inner context handle for further calls to NetSecurity
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
                if (null == negoContext.GssContext)
                {
                    negoContext.SetGssContext(contextHandle);
                }

                // Populate protocol used for authentication
                if (done)
                {
                    negoContext.SetAuthenticationPackage(Convert.ToBoolean(isNtlmUsed));
                }

                SecurityStatusPalErrorCode errorCode = done ?
                                                       (negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
                                                       SecurityStatusPalErrorCode.ContinueNeeded;
                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(null, ex);
                }
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }
示例#17
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential)
     : base(credential)
 {
     Debug.Assert((null != credential), "Null credential in SafeDeleteNegoContext");
 }
        private static SecurityStatusPal EstablishSecurityContext(
          SafeFreeNegoCredentials credential,
          ref SafeDeleteContext context,
          string targetName,
          ContextFlagsPal inFlags,
          SecurityBuffer inputBuffer,
          SecurityBuffer outputBuffer,
          ref ContextFlagsPal outFlags)
        {
            bool isNtlmOnly = credential.IsNtlmOnly;

            if (context == null)
            {
                // Empty target name causes the failure on Linux, hence passing a non-empty string  
                context = isNtlmOnly ? new SafeDeleteNegoContext(credential, credential.UserName) : new SafeDeleteNegoContext(credential, targetName);
            }

            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;
            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer:false);
                uint outputFlags;
                int isNtlmUsed;
                SafeGssContextHandle contextHandle = negoContext.GssContext;
                bool done = GssInitSecurityContext(
                   ref contextHandle,
                   credential.GssCredential,
                   isNtlmOnly,
                   negoContext.TargetName,
                   inputFlags,
                   inputBuffer?.token,
                   out outputBuffer.token,
                   out outputFlags,
                   out isNtlmUsed);

                Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
                outputBuffer.size = outputBuffer.token.Length;
                outputBuffer.offset = 0;
                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags, isServer:false);
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);

                // Save the inner context handle for further calls to NetSecurity
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
                if (null == negoContext.GssContext)
                {
                    negoContext.SetGssContext(contextHandle);
                }

                // Populate protocol used for authentication
                if (done)
                {
                    negoContext.SetAuthenticationPackage(Convert.ToBoolean(isNtlmUsed));
                }

                SecurityStatusPalErrorCode errorCode = done ? 
                    (negoContext.IsNtlmUsed && outputBuffer.size > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) :
                    SecurityStatusPalErrorCode.ContinueNeeded;
                return new SecurityStatusPal(errorCode);
            }
            catch(Exception ex)
            {
                if (NetEventSource.IsEnabled) NetEventSource.Error(null, ex);
                return new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex);
            }
        }
示例#19
0
        private static SecurityStatusPal EstablishSecurityContext(
            SafeFreeNegoCredentials credential,
            ref SafeDeleteContext context,
            bool isNtlm,
            string targetName,
            ContextFlagsPal inFlags,
            SecurityBuffer inputBuffer,
            SecurityBuffer outputBuffer,
            ref ContextFlagsPal outFlags)
        {
            Debug.Assert(!isNtlm, "EstablishSecurityContext: NTLM is not yet supported");

            if (context == null)
            {
                context = new SafeDeleteNegoContext(credential, targetName);
            }

            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context;

            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags);
                uint outputFlags;
                SafeGssContextHandle contextHandle = negoContext.GssContext;
                bool done = Interop.GssApi.EstablishSecurityContext(
                    ref contextHandle,
                    credential.GssCredential,
                    isNtlm,
                    negoContext.TargetName,
                    inputFlags,
                    inputBuffer?.token,
                    out outputBuffer.token,
                    out outputFlags);

                Debug.Assert(outputBuffer.token != null, "Unexpected null buffer returned by GssApi");
                outputBuffer.size   = outputBuffer.token.Length;
                outputBuffer.offset = 0;

                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop((Interop.NetSecurityNative.GssFlags)outputFlags);

                // Save the inner context handle for further calls to NetSecurity
                Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext);
                if (null == negoContext.GssContext)
                {
                    negoContext.SetGssContext(contextHandle);
                }

                SecurityStatusPalErrorCode errorCode = done ? SecurityStatusPalErrorCode.CompleteNeeded : SecurityStatusPalErrorCode.ContinueNeeded;
                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                //TODO (Issue #5890): Print exception until issue is fixed
                Debug.Write("Exception Caught. - " + ex);
                if (GlobalLog.IsEnabled)
                {
                    GlobalLog.Print("Exception Caught. - " + ex);
                }

                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }
示例#20
0
        private static SecurityStatusPal EstablishSecurityContext(
            SafeFreeNegoCredentials credential,
            ref SafeDeleteContext?context,
            ChannelBinding?channelBinding,
            string?targetName,
            ContextFlagsPal inFlags,
            ReadOnlySpan <byte> incomingBlob,
            out byte[]?resultBuffer,
            ref ContextFlagsPal outFlags)
        {
            bool isNtlmOnly = credential.IsNtlmOnly;

            resultBuffer = null;

            if (context == null)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    string protocol = isNtlmOnly ? "NTLM" : "SPNEGO";
                    NetEventSource.Info(context, $"requested protocol = {protocol}, target = {targetName}");
                }

                context = new SafeDeleteNegoContext(credential, targetName !);
            }

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;
            Interop.NetSecurityNative.Status    minorStatus;
            SafeDeleteNegoContext negoContext   = (SafeDeleteNegoContext)context;
            SafeGssContextHandle  contextHandle = negoContext.GssContext;

            try
            {
                Interop.NetSecurityNative.GssFlags inputFlags =
                    ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false);
                uint outputFlags;
                bool isNtlmUsed;

                if (channelBinding != null)
                {
                    // If a TLS channel binding token (cbt) is available then get the pointer
                    // to the application specific data.
                    int appDataOffset = Marshal.SizeOf <SecChannelBindings>();
                    Debug.Assert(appDataOffset < channelBinding.Size);
                    IntPtr cbtAppData     = channelBinding.DangerousGetHandle() + appDataOffset;
                    int    cbtAppDataSize = channelBinding.Size - appDataOffset;
                    status = Interop.NetSecurityNative.InitSecContext(out minorStatus,
                                                                      credential.GssCredential,
                                                                      ref contextHandle,
                                                                      isNtlmOnly,
                                                                      cbtAppData,
                                                                      cbtAppDataSize,
                                                                      negoContext.TargetName,
                                                                      (uint)inputFlags,
                                                                      incomingBlob,
                                                                      ref token,
                                                                      out outputFlags,
                                                                      out isNtlmUsed);
                }
                else
                {
                    status = Interop.NetSecurityNative.InitSecContext(out minorStatus,
                                                                      credential.GssCredential,
                                                                      ref contextHandle,
                                                                      isNtlmOnly,
                                                                      negoContext.TargetName,
                                                                      (uint)inputFlags,
                                                                      incomingBlob,
                                                                      ref token,
                                                                      out outputFlags,
                                                                      out isNtlmUsed);
                }

                if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) &&
                    (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED))
                {
                    if (negoContext.GssContext.IsInvalid)
                    {
                        context.Dispose();
                    }

                    Interop.NetSecurityNative.GssApiException gex = new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(null, gex);
                    }
                    resultBuffer = Array.Empty <byte>();
                    return(new SecurityStatusPal(GetErrorCode(gex), gex));
                }

                resultBuffer = token.ToByteArray();

                if (status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    if (NetEventSource.Log.IsEnabled())
                    {
                        string protocol = isNtlmOnly ? "NTLM" : isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos";
                        NetEventSource.Info(context, $"actual protocol = {protocol}");
                    }

                    // Populate protocol used for authentication
                    negoContext.SetAuthenticationPackage(isNtlmUsed);
                }

                Debug.Assert(resultBuffer != null, "Unexpected null buffer returned by GssApi");
                outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(
                    (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false);

                SecurityStatusPalErrorCode errorCode = status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE ?
                                                       SecurityStatusPalErrorCode.OK :
                                                       SecurityStatusPalErrorCode.ContinueNeeded;
                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(null, ex);
                }
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
            finally
            {
                token.Dispose();

                // Save the inner context handle for further calls to NetSecurity
                //
                // For the first call `negoContext.GssContext` is invalid and we expect the
                // inital handle to be returned from InitSecContext. For any subsequent
                // call the handle should stay the same or it can be destroyed by the native
                // InitSecContext call.
                Debug.Assert(
                    negoContext.GssContext == contextHandle ||
                    negoContext.GssContext.IsInvalid ||
                    contextHandle.IsInvalid);
                negoContext.SetGssContext(contextHandle);
            }
        }