internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, byte[] incomingBlob, ChannelBinding channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { #if netstandard Span <SecurityBuffer> inSecurityBufferSpan = new SecurityBuffer[2]; #else TwoSecurityBuffers twoSecurityBuffers = default; Span <SecurityBuffer> inSecurityBufferSpan = MemoryMarshal.CreateSpan(ref twoSecurityBuffers._item0, 2); #endif int inSecurityBufferSpanLength = 0; if (incomingBlob != null && channelBinding != null) { inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); inSecurityBufferSpan[1] = new SecurityBuffer(channelBinding); inSecurityBufferSpanLength = 2; } else if (incomingBlob != null) { inSecurityBufferSpan[0] = new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN); inSecurityBufferSpanLength = 1; } else if (channelBinding != null) { inSecurityBufferSpan[0] = new SecurityBuffer(channelBinding); inSecurityBufferSpanLength = 1; } inSecurityBufferSpan = inSecurityBufferSpan.Slice(0, inSecurityBufferSpanLength); var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext sslContext = (SafeDeleteSslContext)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, ref credentialsHandle, ref sslContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inSecurityBufferSpan, ref outSecurityBuffer, ref outContextFlags); securityContext = sslContext; resultBlob = outSecurityBuffer.token; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
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) { InputSecurityBuffers inputBuffers = default; if (!incomingBlob.IsEmpty) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext?sslContext = (SafeDeleteSslContext?)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref sslContext, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); // SSPI Workaround // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE // when it should return SEC_E_INVALID_TOKEN. if (winStatus == Interop.SECURITY_STATUS.InvalidHandle && securityContext == null && !incomingBlob.IsEmpty) { winStatus = Interop.SECURITY_STATUS.InvalidToken; } Debug.Assert(outSecurityBuffer.offset == 0); resultBlob = outSecurityBuffer.token; resultBlobLength = outSecurityBuffer.size; securityContext = sslContext; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
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) { InputSecurityBuffers inputBuffers = default; if (!incomingBlob.IsEmpty) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext?sslContext = (SafeDeleteSslContext?)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, ref credentialsHandle, ref sslContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); securityContext = sslContext; Debug.Assert(outSecurityBuffer.offset == 0); resultBlob = outSecurityBuffer.token; resultBlobLength = outSecurityBuffer.size; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, ref ContextFlagsPal contextFlags) { InputSecurityBuffers inputBuffers = default; if (incomingBlob != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (channelBinding != null) { inputBuffers.SetNextBuffer(new InputSecurityBuffer(channelBinding)); } var outSecurityBuffer = new SecurityBuffer(resultBlob, SecurityBufferType.SECBUFFER_TOKEN); Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; // There is only one SafeDeleteContext type on Windows which is SafeDeleteSslContext so this cast is safe. SafeDeleteSslContext?sslContext = (SafeDeleteSslContext?)securityContext; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref sslContext, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inputBuffers, ref outSecurityBuffer, ref outContextFlags); resultBlob = outSecurityBuffer.token; securityContext = sslContext; contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; Interop.SECURITY_STATUS winStatus = (Interop.SECURITY_STATUS)SSPIWrapper.AcceptSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref securityContext, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.SECURITY_NETWORK_DREP, inSecurityBufferArray, outSecurityBuffer, ref outContextFlags); contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
internal static SecurityStatusPal InitializeSecurityContext( SafeFreeCredentials credentialsHandle, ref SafeDeleteContext securityContext, string spn, ContextFlagsPal requestedContextFlags, SecurityBuffer[] inSecurityBufferArray, SecurityBuffer outSecurityBuffer, ref ContextFlagsPal contextFlags) { Interop.SspiCli.ContextFlags outContextFlags = Interop.SspiCli.ContextFlags.Zero; Interop.SecurityStatus winStatus = (Interop.SecurityStatus)SSPIWrapper.InitializeSecurityContext( GlobalSSPI.SSPIAuth, credentialsHandle, ref securityContext, spn, ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(requestedContextFlags), Interop.SspiCli.Endianness.Network, inSecurityBufferArray, outSecurityBuffer, ref outContextFlags); contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop(outContextFlags); return(SecurityStatusAdapterPal.GetSecurityStatusPalFromInterop(winStatus)); }
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)); } }
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)); } }
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); } }
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)); } }