Example #1
0
 internal static extern Status InitSecContext(
     out Status minorStatus,
     SafeGssCredHandle initiatorCredHandle,
     ref SafeGssContextHandle contextHandle,
     bool isNtlmOnly,
     SafeGssNameHandle?targetName,
     uint reqFlags,
     byte[]?inputBytes,
     int inputLength,
     ref GssBuffer token,
     out uint retFlags,
     out bool isNtlmUsed);
Example #2
0
 private static partial Status InitSecContext(
     out Status minorStatus,
     SafeGssCredHandle initiatorCredHandle,
     ref SafeGssContextHandle contextHandle,
     [MarshalAs(UnmanagedType.Bool)] bool isNtlmOnly,
     SafeGssNameHandle?targetName,
     uint reqFlags,
     ref byte inputBytes,
     int inputLength,
     ref GssBuffer token,
     out uint retFlags,
     [MarshalAs(UnmanagedType.Bool)] out bool isNtlmUsed);
        private static bool GssAcceptSecurityContext(
            ref SafeGssContextHandle?context,
            SafeGssCredHandle credential,
            byte[]?buffer,
            out byte[] outputBuffer,
            out uint outFlags,
            out bool isNtlmUsed)
        {
            Debug.Assert(credential != null);

            bool newContext = false;

            if (context == null)
            {
                newContext = true;
                context    = new SafeGssContextHandle();
            }

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;

            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                status = Interop.NetSecurityNative.AcceptSecContext(out minorStatus,
                                                                    credential,
                                                                    ref context,
                                                                    buffer,
                                                                    buffer?.Length ?? 0,
                                                                    ref token,
                                                                    out outFlags,
                                                                    out isNtlmUsed);

                if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) &&
                    (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED))
                {
                    if (newContext)
                    {
                        context.Dispose();
                        context = null;
                    }
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                outputBuffer = token.ToByteArray();
            }
            finally
            {
                token.Dispose();
            }

            return(status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE);
        }
Example #4
0
        internal static bool EstablishSecurityContext(
            ref SafeGssContextHandle context,
            SafeGssCredHandle credential,
            bool isNtlm,
            SafeGssNameHandle targetName,
            Interop.NetSecurityNative.GssFlags inFlags,
            byte[] buffer,
            out byte[] outputBuffer,
            out uint outFlags)
        {
            outputBuffer = null;
            outFlags     = 0;

            // EstablishSecurityContext is called multiple times in a session.
            // In each call, we need to pass the context handle from the previous call.
            // For the first call, the context handle will be null.
            if (context == null)
            {
                context = new SafeGssContextHandle();
            }

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;

            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                status = NetSecurityNative.InitSecContext(out minorStatus,
                                                          credential,
                                                          ref context,
                                                          isNtlm,
                                                          targetName,
                                                          (uint)inFlags,
                                                          buffer,
                                                          (buffer == null) ? 0 : buffer.Length,
                                                          ref token,
                                                          out outFlags);

                if ((status != NetSecurityNative.Status.GSS_S_COMPLETE) && (status != NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED))
                {
                    throw new NetSecurityNative.GssApiException(status, minorStatus);
                }

                outputBuffer = token.ToByteArray();
            }
            finally
            {
                token.Dispose();
            }

            return(status == NetSecurityNative.Status.GSS_S_COMPLETE);
        }
        internal static Status UnwrapBuffer(
            out Status minorStatus,
            SafeGssContextHandle contextHandle,
            byte[] inputBytes,
            int offset,
            int count,
            ref GssBuffer outBuffer)
        {
            Debug.Assert(inputBytes != null, "inputBytes must be valid value");
            Debug.Assert(offset >= 0 && offset <= inputBytes.Length, "offset must be valid");
            Debug.Assert(count >= 0 && count <= inputBytes.Length, "count must be valid");

            return(Unwrap(out minorStatus, contextHandle, inputBytes, offset, count, ref outBuffer));
        }
Example #6
0
 public SafeDeleteNegoContext(SafeFreeNegoCredentials credential, string targetName)
     : this(credential)
 {
     try
     {
         _targetName = SafeGssNameHandle.CreateTarget(targetName);
         _context    = new SafeGssContextHandle();
     }
     catch
     {
         Dispose();
         throw;
     }
 }
 internal static Status InitSecContext(
     out Status minorStatus,
     SafeGssCredHandle initiatorCredHandle,
     ref SafeGssContextHandle contextHandle,
     bool isNtlmOnly,
     IntPtr cbt,
     int cbtSize,
     SafeGssNameHandle targetName,
     uint reqFlags,
     byte[] inputBytes,
     int inputLength,
     ref GssBuffer token,
     out uint retFlags,
     out int isNtlmUsed) => throw new PlatformNotSupportedException();
 internal static extern Status InitSecContext(
     out Status minorStatus,
     SafeGssCredHandle initiatorCredHandle,
     ref SafeGssContextHandle contextHandle,
     bool isNtlmOnly,
     IntPtr cbt,
     int cbtSize,
     bool isNtlmFallback,
     SafeGssNameHandle targetNameKerberos,
     SafeGssNameHandle targetNameNtlm,
     uint reqFlags,
     byte[] inputBytes,
     int inputLength,
     ref GssBuffer token,
     out uint retFlags,
     out bool isNtlmUsed);
Example #9
0
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (null != _context)
                {
                    _context.Dispose();
                    _context = null;
                }

                if (_targetName != null)
                {
                    _targetName.Dispose();
                    _targetName = null;
                }
            }
            base.Dispose(disposing);
        }
        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);
        }
Example #11
0
 internal static Status AcceptSecContext(
     out Status minorStatus,
     SafeGssCredHandle acceptorCredHandle,
     ref SafeGssContextHandle acceptContextHandle,
     ReadOnlySpan <byte> inputBytes,
     ref GssBuffer token,
     out uint retFlags,
     out bool isNtlmUsed)
 {
     return(AcceptSecContext(
                out minorStatus,
                acceptorCredHandle,
                ref acceptContextHandle,
                ref MemoryMarshal.GetReference(inputBytes),
                inputBytes.Length,
                ref token,
                out retFlags,
                out isNtlmUsed));
 }
        private static string GetUser(
            ref SafeDeleteContext securityContext)
        {
            SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)securityContext;

            try
            {
                SafeGssContextHandle contextHandle = negoContext.GssContext;
                return(GssGetUser(ref contextHandle));
            }
            catch (Exception ex)
            {
                if (NetEventSource.IsEnabled)
                {
                    NetEventSource.Error(null, ex);
                }
                throw;
            }
        }
        private static bool EstablishSecurityContext(
            ref SafeGssContextHandle context,
            byte[] buffer,
            out byte[] outputBuffer)
        {
            outputBuffer = null;

            // EstablishSecurityContext is called multiple times in a session.
            // In each call, we need to pass the context handle from the previous call.
            // For the first call, the context handle will be null.
            if (context == null)
            {
                context = new SafeGssContextHandle();
            }

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;

            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                status = Interop.NetSecurityNative.AcceptSecContext(out minorStatus,
                                                                    ref context,
                                                                    buffer,
                                                                    (buffer == null) ? 0 : buffer.Length,
                                                                    ref token);

                if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) && (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED))
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                outputBuffer = token.ToByteArray();
            }
            finally
            {
                token.Dispose();
            }

            return(status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE);
        }
        internal static NegotiateAuthenticationStatusCode Unwrap(
            SafeDeleteContext securityContext,
            ReadOnlySpan <byte> input,
            IBufferWriter <byte> outputWriter,
            out bool isEncrypted)
        {
            SafeGssContextHandle gssContext = ((SafeDeleteNegoContext)securityContext).GssContext !;

            Interop.NetSecurityNative.GssBuffer decryptedBuffer = default(Interop.NetSecurityNative.GssBuffer);
            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.UnwrapBuffer(out minorStatus, gssContext, out isEncrypted, input, ref decryptedBuffer);
                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    return(status switch
                    {
                        Interop.NetSecurityNative.Status.GSS_S_BAD_SIG => NegotiateAuthenticationStatusCode.MessageAltered,
                        _ => NegotiateAuthenticationStatusCode.InvalidToken
                    });
                }
Example #15
0
        private static byte[] GssWrap(
            SafeGssContextHandle context,
            ref bool encrypt,
            ReadOnlySpan <byte> buffer)
        {
            Interop.NetSecurityNative.GssBuffer encryptedBuffer = default;
            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.WrapBuffer(out minorStatus, context, ref encrypt, buffer, ref encryptedBuffer);
                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                return(encryptedBuffer.ToByteArray());
            }
            finally
            {
                encryptedBuffer.Dispose();
            }
        }
        private static byte[] WrapMessage(SafeGssContextHandle context, byte[] message)
        {
            Interop.NetSecurityNative.GssBuffer wrapped = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;

            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                status = Interop.NetSecurityNative.WrapBuffer(out minorStatus,
                                                              context, false, message, 0, message.Length, ref wrapped);
                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                return(wrapped.ToByteArray());
            }
            finally
            {
                wrapped.Dispose();
            }
        }
Example #17
0
        private static int GssUnwrap(
            SafeGssContextHandle context,
            out bool encrypt,
            Span <byte> buffer)
        {
            Interop.NetSecurityNative.GssBuffer decryptedBuffer = default(Interop.NetSecurityNative.GssBuffer);
            try
            {
                Interop.NetSecurityNative.Status minorStatus;
                Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.UnwrapBuffer(out minorStatus, context, out encrypt, buffer, ref decryptedBuffer);
                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                decryptedBuffer.Span.CopyTo(buffer);
                return(decryptedBuffer.Span.Length);
            }
            finally
            {
                decryptedBuffer.Dispose();
            }
        }
Example #18
0
        internal static int Decrypt(
            SafeDeleteContext securityContext,
            Span <byte> buffer,
            bool isConfidential,
            bool isNtlm,
            out int newOffset)
        {
            SafeGssContextHandle gssContext = ((SafeDeleteNegoContext)securityContext).GssContext !;

            if (isNtlm && !isConfidential)
            {
                const int NtlmSignatureLength = 16;

                if (buffer.Length < NtlmSignatureLength)
                {
                    Debug.Fail("Argument 'count' out of range.");
                    throw new Interop.NetSecurityNative.GssApiException(Interop.NetSecurityNative.Status.GSS_S_DEFECTIVE_TOKEN, 0);
                }

                Interop.NetSecurityNative.Status minorStatus;
                Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.VerifyMic(
                    out minorStatus,
                    gssContext,
                    buffer.Slice(NtlmSignatureLength),
                    buffer.Slice(0, NtlmSignatureLength));
                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                newOffset = NtlmSignatureLength;
                return(buffer.Length - NtlmSignatureLength);
            }

            newOffset = 0;
            return(GssUnwrap(gssContext, out _, buffer));
        }
        private static string GssGetUser(
            ref SafeGssContextHandle context)
        {
            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);

            try
            {
                Interop.NetSecurityNative.Status status
                    = Interop.NetSecurityNative.GetUser(out var minorStatus,
                                                        context,
                                                        ref token);

                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                ReadOnlySpan <byte> tokenBytes = token.Span;
                int length = tokenBytes.Length;
                if (length > 0 && tokenBytes[length - 1] == '\0')
                {
                    // Some GSS-API providers (gss-ntlmssp) include the terminating null with strings, so skip that.
                    tokenBytes = tokenBytes.Slice(0, length - 1);
                }

#if NETSTANDARD2_0
                return(Encoding.UTF8.GetString(tokenBytes.ToArray(), 0, tokenBytes.Length));
#else
                return(Encoding.UTF8.GetString(tokenBytes));
#endif
            }
            finally
            {
                token.Dispose();
            }
        }
Example #20
0
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (null != _context)
                {
                    _context.Dispose();
                    _context = null;
                }

                if (_targetNameKerberos != null)
                {
                    _targetNameKerberos.Dispose();
                    _targetNameKerberos = null;
                }

                if (_targetNameNtlm != null)
                {
                    _targetNameNtlm.Dispose();
                    _targetNameNtlm = null;
                }
            }
            base.Dispose(disposing);
        }
        private static string GssGetUser(
            ref SafeGssContextHandle context)
        {
            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);

            try
            {
                Interop.NetSecurityNative.Status status
                    = Interop.NetSecurityNative.GetUser(out var minorStatus,
                                                        context,
                                                        ref token);

                if (status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE)
                {
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                return(Encoding.UTF8.GetString(token.ToByteArray()));
            }
            finally
            {
                token.Dispose();
            }
        }
Example #22
0
        private static bool GssInitSecurityContext(
            ref SafeGssContextHandle?context,
            SafeGssCredHandle credential,
            bool isNtlm,
            ChannelBinding?channelBinding,
            SafeGssNameHandle?targetName,
            Interop.NetSecurityNative.GssFlags inFlags,
            byte[]?buffer,
            out byte[]?outputBuffer,
            out uint outFlags,
            out bool isNtlmUsed)
        {
            outputBuffer = null;
            outFlags     = 0;

            // EstablishSecurityContext is called multiple times in a session.
            // In each call, we need to pass the context handle from the previous call.
            // For the first call, the context handle will be null.
            bool newContext = false;

            if (context == null)
            {
                newContext = true;
                context    = new SafeGssContextHandle();
            }

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            Interop.NetSecurityNative.Status    status;

            try
            {
                Interop.NetSecurityNative.Status minorStatus;

                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,
                                                                      ref context,
                                                                      isNtlm,
                                                                      cbtAppData,
                                                                      cbtAppDataSize,
                                                                      targetName,
                                                                      (uint)inFlags,
                                                                      buffer,
                                                                      (buffer == null) ? 0 : buffer.Length,
                                                                      ref token,
                                                                      out outFlags,
                                                                      out isNtlmUsed);
                }
                else
                {
                    status = Interop.NetSecurityNative.InitSecContext(out minorStatus,
                                                                      credential,
                                                                      ref context,
                                                                      isNtlm,
                                                                      targetName,
                                                                      (uint)inFlags,
                                                                      buffer,
                                                                      (buffer == null) ? 0 : buffer.Length,
                                                                      ref token,
                                                                      out outFlags,
                                                                      out isNtlmUsed);
                }

                if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) &&
                    (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED))
                {
                    if (newContext)
                    {
                        context.Dispose();
                        context = null;
                    }
                    throw new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                }

                outputBuffer = token.ToByteArray();
            }
            finally
            {
                token.Dispose();
            }

            return(status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE);
        }
 internal static extern Status AcceptSecContext(
     out Status minorStatus,
     ref SafeGssContextHandle acceptContextHandle,
     byte[] inputBytes,
     int inputLength,
     ref GssBuffer token);
Example #24
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));
            }
        }
Example #25
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);
            }
        }
Example #26
0
        internal static SecurityStatusPal AcceptSecurityContext(
            SafeFreeCredentials?credentialsHandle,
            ref SafeDeleteContext?securityContext,
            ContextFlagsPal requestedContextFlags,
            ReadOnlySpan <byte> incomingBlob,
            ChannelBinding?channelBinding,
            ref byte[] resultBlob,
            out int resultBlobLength,
            ref ContextFlagsPal contextFlags)
        {
            securityContext ??= new SafeDeleteNegoContext((SafeFreeNegoCredentials)credentialsHandle !);

            SafeDeleteNegoContext negoContext   = (SafeDeleteNegoContext)securityContext;
            SafeGssContextHandle  contextHandle = negoContext.GssContext;

            Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer);
            try
            {
                Interop.NetSecurityNative.Status status;
                Interop.NetSecurityNative.Status minorStatus;
                status = Interop.NetSecurityNative.AcceptSecContext(out minorStatus,
                                                                    negoContext.AcceptorCredential,
                                                                    ref contextHandle,
                                                                    incomingBlob,
                                                                    ref token,
                                                                    out uint outputFlags,
                                                                    out bool isNtlmUsed);

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

                    Interop.NetSecurityNative.GssApiException gex = new Interop.NetSecurityNative.GssApiException(status, minorStatus);
                    if (NetEventSource.Log.IsEnabled())
                    {
                        NetEventSource.Error(null, gex);
                    }
                    resultBlobLength = 0;
                    return(new SecurityStatusPal(GetErrorCode(gex), gex));
                }

                resultBlob = token.ToByteArray();

                Debug.Assert(resultBlob != null, "Unexpected null buffer returned by GssApi");

                contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(
                    (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: true);
                resultBlobLength = resultBlob.Length;

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

                    negoContext.SetAuthenticationPackage(isNtlmUsed);
                    errorCode = SecurityStatusPalErrorCode.OK;
                }
                else
                {
                    errorCode = SecurityStatusPalErrorCode.ContinueNeeded;
                }

                return(new SecurityStatusPal(errorCode));
            }
            catch (Exception ex)
            {
                if (NetEventSource.Log.IsEnabled())
                {
                    NetEventSource.Error(null, ex);
                }
                resultBlobLength = 0;
                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 AcceptSecContext. For any subsequent
                // call the handle should stay the same or it can be destroyed by the native
                // AcceptSecContext call.
                Debug.Assert(
                    negoContext.GssContext == contextHandle ||
                    negoContext.GssContext.IsInvalid ||
                    contextHandle.IsInvalid);
                negoContext.SetGssContext(contextHandle);
            }
        }
Example #27
0
 public void SetGssContext(SafeGssContextHandle context)
 {
     Debug.Assert(context != null && !context.IsInvalid, "Invalid context passed to SafeDeleteNegoContext");
     _context = context;
 }
Example #28
0
 internal static extern Status GetUser(
     out Status minorStatus,
     SafeGssContextHandle acceptContextHandle,
     ref GssBuffer token);
Example #29
0
 internal static Status AcceptSecContext(
     out Status minorStatus,
     ref SafeGssContextHandle acceptContextHandle,
     byte[] inputBytes,
     int inputLength,
     ref GssBuffer token) => throw new NotSupportedException();
        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.IsEnabled)
                {
                    string protocol = isNtlmOnly ? "NTLM" : "SPNEGO";
                    NetEventSource.Info(null, $"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.IsEnabled)
                    {
                        string protocol = isNtlmOnly ? "NTLM" : isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos";
                        NetEventSource.Info(null, $"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.IsEnabled)
                {
                    NetEventSource.Error(null, ex);
                }
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex));
            }
        }