private static byte[] GssWrap( SafeGssContextHandle?context, bool encrypt, byte[] buffer, int offset, int count) { Debug.Assert((buffer != null) && (buffer.Length > 0), "Invalid input buffer passed to Encrypt"); Debug.Assert((offset >= 0) && (offset < buffer.Length), "Invalid input offset passed to Encrypt"); Debug.Assert((count >= 0) && (count <= (buffer.Length - offset)), "Invalid input count passed to Encrypt"); Interop.NetSecurityNative.GssBuffer encryptedBuffer = default(Interop.NetSecurityNative.GssBuffer); try { Interop.NetSecurityNative.Status minorStatus; Interop.NetSecurityNative.Status status = Interop.NetSecurityNative.WrapBuffer(out minorStatus, context, encrypt, buffer, offset, count, 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 bool GssInitSecurityContext( ref SafeGssContextHandle context, SafeGssCredHandle credential, bool isNtlm, SafeGssNameHandle targetName, Interop.NetSecurityNative.GssFlags inFlags, byte[] buffer, out byte[] outputBuffer, out uint outFlags, out int 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. if (context == null) { context = new SafeGssContextHandle(); } Interop.NetSecurityNative.GssBuffer token = default; Interop.NetSecurityNative.Status status; try { Interop.NetSecurityNative.Status minorStatus; 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)) { throw new Interop.NetSecurityNative.GssApiException(status, minorStatus); } outputBuffer = token.ToByteArray(); } finally { token.Dispose(); } return(status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE); }
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); }
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); }
private static byte[] GssWrap( SafeGssContextHandle?context, 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, 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(); } }
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(); } }
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 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); } }
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); } }