internal string?GetOutgoingBlob(string?incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { byte[]? decodedIncomingBlob = null; if (incomingBlob != null && incomingBlob.Length > 0) { decodedIncomingBlob = Convert.FromBase64String(incomingBlob); } byte[]? decodedOutgoingBlob = null; if ((IsValidContext || IsCompleted) && decodedIncomingBlob == null) { // we tried auth previously, now we got a null blob, we're done. this happens // with Kerberos & valid credentials on the domain but no ACLs on the resource _isCompleted = true; statusCode = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); } else { decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, throwOnError, out statusCode); } string?outgoingBlob = null; if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) { outgoingBlob = Convert.ToBase64String(decodedOutgoingBlob); } if (IsCompleted) { CloseContext(); } return(outgoingBlob); }
internal SafeDeleteContext GetContext(out SecurityStatusPal status) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); if (!(IsCompleted && IsValidContext)) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |Should be called only when completed with success, currently is not!"); } if (!IsServer) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |The method must not be called by the client side!"); } if (!IsValidContext) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidHandle); return(null); } return(_securityContext); }
internal static Interop.SecurityStatus GetInteropFromSecurityStatusPal(SecurityStatusPal status) { Interop.SecurityStatus interopStatus; if (!s_statusDictionary.TryGetBackward(status.ErrorCode, out interopStatus)) { Debug.Fail("Unknown SecurityStatus value: " + status); throw new InternalException(); } return interopStatus; }
internal static Interop.SECURITY_STATUS GetInteropFromSecurityStatusPal(SecurityStatusPal status) { Interop.SECURITY_STATUS interopStatus; if (!s_statusDictionary.TryGetBackward(status.ErrorCode, out interopStatus)) { Debug.Fail("Unknown SecurityStatus value: " + status); throw new InternalException(status.ErrorCode); } return(interopStatus); }
public static SecurityStatusPal DecryptMessage(SafeDeleteContext securityContext, byte[] buffer, ref int offset, ref int count) { int resultSize; SecurityStatusPal retVal = EncryptDecryptHelper(securityContext, buffer, offset, count, 0, 0, false, out resultSize); if (SecurityStatusPal.OK == retVal || SecurityStatusPal.Renegotiate == retVal) { count = resultSize; } return(retVal); }
internal SafeDeleteContext?GetContext(out SecurityStatusPal status) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); Debug.Assert(IsCompleted && IsValidContext, "Should be called only when completed with success, currently is not!"); Debug.Assert(IsServer, "The method must not be called by the client side!"); if (!IsValidContext) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidHandle); return(null); } return(_securityContext); }
public static Exception GetException(SecurityStatusPal status) { int win32Code = (int)GetInteropFromSecurityStatusPal(status); return new Win32Exception(win32Code); }
public static Exception GetException(SecurityStatusPal status) { return(status.Exception ?? new Interop.OpenSsl.SslException((int)status.ErrorCode)); }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { if (NetEventSource.IsEnabled) NetEventSource.Enter(this, incomingBlob); var list = new List<SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (_channelBinding != null) { list.Add(new SecurityBuffer(_channelBinding)); } SecurityBuffer[] inSecurityBufferArray = null; if (list.Count > 0) { inSecurityBufferArray = list.ToArray(); } var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.SECBUFFER_TOKEN); bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SSPIWrapper.InitializeSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, inSecurityBuffers); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SSPIWrapper.CompleteAuthToken() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); outSecurityBuffer.token = null; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SSPIWrapper.AcceptSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime && _credentialsHandle != null) { _credentialsHandle.Dispose(); } } if (NegoState.IsError(statusCode)) { CloseContext(); _isCompleted = true; if (throwOnError) { Exception exception = NegotiateStreamPal.CreateExceptionFromError(statusCode); if (NetEventSource.IsEnabled) NetEventSource.Exit(this, exception); throw exception; } if (NetEventSource.IsEnabled) NetEventSource.Exit(this, $"null statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); return null; } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value will tell us correctly if the handshake is over or not if (statusCode.ErrorCode == SecurityStatusPalErrorCode.OK) { // Success. _isCompleted = true; } else if (NetEventSource.IsEnabled) { // We need to continue. if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"need continue statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode}) _securityContext:{_securityContext}"); } if (NetEventSource.IsEnabled) { if (NetEventSource.IsEnabled) NetEventSource.Exit(this, $"IsCompleted: {IsCompleted}"); } return outSecurityBuffer.token; }
public static Exception GetException(SecurityStatusPal status) { return new Win32Exception((int)status); }
public static Exception GetException(SecurityStatusPal status) { int win32Code = (int)GetInteropFromSecurityStatusPal(status); return(new Win32Exception(win32Code)); }
public static Exception GetException(SecurityStatusPal status) { return(new Interop.OpenSsl.SslException((int)status)); }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[]? GetOutgoingBlob(byte[]?incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { return(GetOutgoingBlob(incomingBlob.AsSpan(), throwOnError, out statusCode)); }
internal unsafe string?GetOutgoingBlob(string?incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { Debug.Assert(!IsCompleted); byte[]? decodedIncomingBlob = null; if (incomingBlob != null && incomingBlob.Length > 0) { decodedIncomingBlob = Convert.FromBase64String(incomingBlob); } byte[]? decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, throwOnError, out statusCode); string?outgoingBlob = null; if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) { outgoingBlob = Convert.ToBase64String(decodedOutgoingBlob); } if (IsCompleted) { CloseContext(); } return(outgoingBlob); }
internal byte[]? GetOutgoingBlob(ReadOnlySpan <byte> incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { _tokenBuffer ??= _tokenSize == 0 ? Array.Empty <byte>() : new byte[_tokenSize]; bool firstTime = _securityContext == null; int resultBlobLength; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( ref _credentialsHandle !, ref _securityContext, _spn, _requestedContextFlags, incomingBlob, _channelBinding, ref _tokenBuffer, out resultBlobLength, ref _contextFlags); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"SSPIWrapper.InitializeSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, _tokenBuffer.AsSpan(0, resultBlobLength)); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"SSPIWrapper.CompleteAuthToken() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } resultBlobLength = 0; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, incomingBlob, _channelBinding, ref _tokenBuffer, out resultBlobLength, ref _contextFlags); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"SSPIWrapper.AcceptSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime) { _credentialsHandle?.Dispose(); } } if (((int)statusCode.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory)) { CloseContext(); _isCompleted = true; _tokenBuffer = null; if (throwOnError) { throw NegotiateStreamPal.CreateExceptionFromError(statusCode); } return(null); } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } byte[]? result = resultBlobLength == 0 || _tokenBuffer == null ? null : _tokenBuffer.Length == resultBlobLength ? _tokenBuffer : _tokenBuffer[0..resultBlobLength];
public static Exception GetException(SecurityStatusPal status) { return status.Exception ?? new Interop.OpenSsl.SslException((int)status.ErrorCode); }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes"); } var list = new List<SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN)); } if (_channelBinding != null) { list.Add(new SecurityBuffer(_channelBinding)); } SecurityBuffer[] inSecurityBufferArray = null; if (list.Count > 0) { inSecurityBufferArray = list.ToArray(); } var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.SECBUFFER_TOKEN); bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, inSecurityBuffers); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } outSecurityBuffer.token = null; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime && _credentialsHandle != null) { _credentialsHandle.Dispose(); } } if (NegoState.IsError(statusCode)) { CloseContext(); _isCompleted = true; if (throwOnError) { Exception exception = NegotiateStreamPal.CreateExceptionFromError(statusCode); if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); } throw exception; } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } return null; } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value will tell us correctly if the handshake is over or not if (statusCode.ErrorCode == SecurityStatusPalErrorCode.OK) { // Success. _isCompleted = true; } else if (GlobalLog.IsEnabled) { // We need to continue. GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:" + LoggingHash.ObjectToString(_securityContext) + "]"); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); } return outSecurityBuffer.token; }
internal SafeDeleteContext GetContext(out SecurityStatusPal status) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); if (!(IsCompleted && IsValidContext)) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |Should be called only when completed with success, currently is not!"); } if (!IsServer) { if (GlobalLog.IsEnabled) { GlobalLog.AssertFormat("NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", LoggingHash.HashString(this)); } Debug.Fail("NTAuthentication#" + LoggingHash.HashString(this) + "::GetContextToken |The method must not be called by the client side!"); } if (!IsValidContext) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidHandle); return null; } return _securityContext; }
private static Interop.SecurityStatus GetInteropFromSecurityStatusPal(SecurityStatusPal status) { switch (status) { case SecurityStatusPal.NotSet: Debug.Fail("SecurityStatus NotSet"); throw new InternalException(); case SecurityStatusPal.OK: return Interop.SecurityStatus.OK; case SecurityStatusPal.ContinueNeeded: return Interop.SecurityStatus.ContinueNeeded; case SecurityStatusPal.CompleteNeeded: return Interop.SecurityStatus.CompleteNeeded; case SecurityStatusPal.CompAndContinue: return Interop.SecurityStatus.CompAndContinue; case SecurityStatusPal.ContextExpired: return Interop.SecurityStatus.ContextExpired; case SecurityStatusPal.CredentialsNeeded: return Interop.SecurityStatus.CredentialsNeeded; case SecurityStatusPal.Renegotiate: return Interop.SecurityStatus.Renegotiate; case SecurityStatusPal.OutOfMemory: return Interop.SecurityStatus.OutOfMemory; case SecurityStatusPal.InvalidHandle: return Interop.SecurityStatus.InvalidHandle; case SecurityStatusPal.Unsupported: return Interop.SecurityStatus.Unsupported; case SecurityStatusPal.TargetUnknown: return Interop.SecurityStatus.TargetUnknown; case SecurityStatusPal.InternalError: return Interop.SecurityStatus.InternalError; case SecurityStatusPal.PackageNotFound: return Interop.SecurityStatus.PackageNotFound; case SecurityStatusPal.NotOwner: return Interop.SecurityStatus.NotOwner; case SecurityStatusPal.CannotInstall: return Interop.SecurityStatus.CannotInstall; case SecurityStatusPal.InvalidToken: return Interop.SecurityStatus.InvalidToken; case SecurityStatusPal.CannotPack: return Interop.SecurityStatus.CannotPack; case SecurityStatusPal.QopNotSupported: return Interop.SecurityStatus.QopNotSupported; case SecurityStatusPal.NoImpersonation: return Interop.SecurityStatus.NoImpersonation; case SecurityStatusPal.LogonDenied: return Interop.SecurityStatus.LogonDenied; case SecurityStatusPal.UnknownCredentials: return Interop.SecurityStatus.UnknownCredentials; case SecurityStatusPal.NoCredentials: return Interop.SecurityStatus.NoCredentials; case SecurityStatusPal.MessageAltered: return Interop.SecurityStatus.MessageAltered; case SecurityStatusPal.OutOfSequence: return Interop.SecurityStatus.OutOfSequence; case SecurityStatusPal.NoAuthenticatingAuthority: return Interop.SecurityStatus.NoAuthenticatingAuthority; case SecurityStatusPal.IncompleteMessage: return Interop.SecurityStatus.IncompleteMessage; case SecurityStatusPal.IncompleteCredentials: return Interop.SecurityStatus.IncompleteCredentials; case SecurityStatusPal.BufferNotEnough: return Interop.SecurityStatus.BufferNotEnough; case SecurityStatusPal.WrongPrincipal: return Interop.SecurityStatus.WrongPrincipal; case SecurityStatusPal.TimeSkew: return Interop.SecurityStatus.TimeSkew; case SecurityStatusPal.UntrustedRoot: return Interop.SecurityStatus.UntrustedRoot; case SecurityStatusPal.IllegalMessage: return Interop.SecurityStatus.IllegalMessage; case SecurityStatusPal.CertUnknown: return Interop.SecurityStatus.CertUnknown; case SecurityStatusPal.CertExpired: return Interop.SecurityStatus.CertExpired; case SecurityStatusPal.AlgorithmMismatch: return Interop.SecurityStatus.AlgorithmMismatch; case SecurityStatusPal.SecurityQosFailed: return Interop.SecurityStatus.SecurityQosFailed; case SecurityStatusPal.SmartcardLogonRequired: return Interop.SecurityStatus.SmartcardLogonRequired; case SecurityStatusPal.UnsupportedPreauth: return Interop.SecurityStatus.UnsupportedPreauth; case SecurityStatusPal.BadBinding: return Interop.SecurityStatus.BadBinding; default: Debug.Fail("Unknown Interop.SecurityStatus value: " + status); throw new InternalException(); } }
public static Exception GetException(SecurityStatusPal status) { return new Interop.OpenSsl.SslException((int)status); }
internal unsafe byte[]? GetOutgoingBlob(ReadOnlySpan <byte> incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { byte[]? outgoingBlob; // TODO: Logging, validation if (_negotiateMessage == null) { Debug.Assert(incomingBlob.IsEmpty); _negotiateMessage = new byte[sizeof(NegotiateMessage)]; CreateNtlmNegotiateMessage(_negotiateMessage); outgoingBlob = _isSpNego ? CreateSpNegoNegotiateMessage(_negotiateMessage) : _negotiateMessage; statusCode = SecurityStatusPalContinueNeeded; } else { Debug.Assert(!incomingBlob.IsEmpty); if (!_isSpNego) { IsCompleted = true; outgoingBlob = ProcessChallenge(incomingBlob, out statusCode); } else { outgoingBlob = ProcessSpNegoChallenge(incomingBlob, out statusCode); } } if (statusCode.ErrorCode >= SecurityStatusPalErrorCode.OutOfMemory && throwOnError) { throw new Win32Exception(NTE_FAIL, statusCode.ErrorCode.ToString()); } return(outgoingBlob); }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this, incomingBlob); } SecurityBuffer[] inSecurityBufferArray = null; if (incomingBlob != null && _channelBinding != null) { inSecurityBufferArray = new SecurityBuffer[2] { new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN), new SecurityBuffer(_channelBinding) }; } else if (incomingBlob != null) { inSecurityBufferArray = new SecurityBuffer[1] { new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN) }; } else if (_channelBinding != null) { inSecurityBufferArray = new SecurityBuffer[1] { new SecurityBuffer(_channelBinding) }; } var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.SECBUFFER_TOKEN); bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"SSPIWrapper.InitializeSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, inSecurityBuffers); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"SSPIWrapper.CompleteAuthToken() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } outSecurityBuffer.token = null; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"SSPIWrapper.AcceptSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime && _credentialsHandle != null) { _credentialsHandle.Dispose(); } } if (((int)statusCode.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory)) { CloseContext(); _isCompleted = true; if (throwOnError) { Exception exception = NegotiateStreamPal.CreateExceptionFromError(statusCode); if (NetEventSource.IsEnabled) { NetEventSource.Exit(this, exception); } throw exception; } if (NetEventSource.IsEnabled) { NetEventSource.Exit(this, $"null statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } return(null); } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value will tell us correctly if the handshake is over or not if (statusCode.ErrorCode == SecurityStatusPalErrorCode.OK) { // Success. _isCompleted = true; } else if (NetEventSource.IsEnabled) { // We need to continue. if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"need continue statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode}) _securityContext:{_securityContext}"); } } if (NetEventSource.IsEnabled) { if (NetEventSource.IsEnabled) { NetEventSource.Exit(this, $"IsCompleted: {IsCompleted}"); } } return(outSecurityBuffer.token); }
internal HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "HandleAuthentication() memoryBlob:0x" + ((IntPtr)memoryBlob.RequestBlob).ToString("x")); string challenge = null; stoleBlob = false; // Some things we need right away. Lift them out now while it's convenient. string verb = Interop.HttpApi.GetVerb(memoryBlob.RequestBlob); string authorizationHeader = Interop.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, (int)HttpRequestHeader.Authorization); ulong connectionId = memoryBlob.RequestBlob->ConnectionId; ulong requestId = memoryBlob.RequestBlob->RequestId; bool isSecureConnection = memoryBlob.RequestBlob->pSslInfo != null; if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"HandleAuthentication() authorizationHeader: ({authorizationHeader})"); // if the app has turned on AuthPersistence, an anonymous request might // be authenticated by virtue of it coming on a connection that was // previously authenticated. // assurance that we do this only for NTLM/Negotiate is not here, but in the // code that caches WindowsIdentity instances in the Dictionary. DisconnectAsyncResult disconnectResult; DisconnectResults.TryGetValue(connectionId, out disconnectResult); if (UnsafeConnectionNtlmAuthentication) { if (authorizationHeader == null) { WindowsPrincipal principal = disconnectResult?.AuthenticatedConnection; if (principal != null) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Principal: {principal} principal.Identity.Name: {principal.Identity.Name} creating request"); stoleBlob = true; HttpListenerContext ntlmContext = new HttpListenerContext(this, memoryBlob); ntlmContext.SetIdentity(principal, null); ntlmContext.Request.ReleasePins(); return ntlmContext; } } else { // They sent an authorization - destroy their previous credentials. if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Clearing principal cache"); if (disconnectResult != null) { disconnectResult.AuthenticatedConnection = null; } } } // Figure out what schemes we're allowing, what context we have. stoleBlob = true; HttpListenerContext httpContext = null; NTAuthentication oldContext = null; NTAuthentication newContext = null; NTAuthentication context = null; AuthenticationSchemes headerScheme = AuthenticationSchemes.None; AuthenticationSchemes authenticationScheme = AuthenticationSchemes; ExtendedProtectionPolicy extendedProtectionPolicy = _extendedProtectionPolicy; try { // Take over handling disconnects for now. if (disconnectResult != null && !disconnectResult.StartOwningDisconnectHandling()) { // Just disconnected just then. Pretend we didn't see the disconnectResult. disconnectResult = null; } // Pick out the old context now. By default, it'll be removed in the finally, unless context is set somewhere. if (disconnectResult != null) { oldContext = disconnectResult.Session; } httpContext = new HttpListenerContext(this, memoryBlob); AuthenticationSchemeSelector authenticationSelector = _authenticationDelegate; if (authenticationSelector != null) { try { httpContext.Request.ReleasePins(); authenticationScheme = authenticationSelector(httpContext.Request); // Cache the results of authenticationSelector (if any) httpContext.AuthenticationSchemes = authenticationScheme; if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"AuthenticationScheme: {authenticationScheme}"); } catch (Exception exception) when (!ExceptionCheck.IsFatal(exception)) { if (NetEventSource.IsEnabled) { NetEventSource.Error(this, SR.Format(SR.net_log_listener_delegate_exception, exception)); NetEventSource.Info(this, $"authenticationScheme: {authenticationScheme}"); } SendError(requestId, HttpStatusCode.InternalServerError, null); httpContext.Close(); return null; } } else { // We didn't give the request to the user yet, so we haven't lost control of the unmanaged blob and can // continue to reuse the buffer. stoleBlob = false; } ExtendedProtectionSelector extendedProtectionSelector = _extendedProtectionSelectorDelegate; if (extendedProtectionSelector != null) { extendedProtectionPolicy = extendedProtectionSelector(httpContext.Request); if (extendedProtectionPolicy == null) { extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never); } // Cache the results of extendedProtectionSelector (if any) httpContext.ExtendedProtectionPolicy = extendedProtectionPolicy; } // Then figure out what scheme they're trying (if any are allowed) int index = -1; if (authorizationHeader != null && (authenticationScheme & ~AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None) { // Find the end of the scheme name. Trust that HTTP.SYS parsed out just our header ok. for (index = 0; index < authorizationHeader.Length; index++) { if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' || authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n') { break; } } // Currently only allow one Authorization scheme/header per request. if (index < authorizationHeader.Length) { if ((authenticationScheme & AuthenticationSchemes.Negotiate) != AuthenticationSchemes.None && string.Compare(authorizationHeader, 0, AuthenticationTypes.Negotiate, 0, index, StringComparison.OrdinalIgnoreCase) == 0) { headerScheme = AuthenticationSchemes.Negotiate; } else if ((authenticationScheme & AuthenticationSchemes.Ntlm) != AuthenticationSchemes.None && string.Compare(authorizationHeader, 0, AuthenticationTypes.NTLM, 0, index, StringComparison.OrdinalIgnoreCase) == 0) { headerScheme = AuthenticationSchemes.Ntlm; } else if ((authenticationScheme & AuthenticationSchemes.Basic) != AuthenticationSchemes.None && string.Compare(authorizationHeader, 0, AuthenticationTypes.Basic, 0, index, StringComparison.OrdinalIgnoreCase) == 0) { headerScheme = AuthenticationSchemes.Basic; } else { if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_unsupported_authentication_scheme, authorizationHeader, authenticationScheme)); } } } // httpError holds the error we will return if an Authorization header is present but can't be authenticated HttpStatusCode httpError = HttpStatusCode.InternalServerError; bool error = false; // See if we found an acceptable auth header if (headerScheme == AuthenticationSchemes.None) { if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_unmatched_authentication_scheme, authenticationScheme.ToString(), (authorizationHeader == null ? "<null>" : authorizationHeader))); // If anonymous is allowed, just return the context. Otherwise go for the 401. if ((authenticationScheme & AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None) { if (!stoleBlob) { stoleBlob = true; httpContext.Request.ReleasePins(); } return httpContext; } httpError = HttpStatusCode.Unauthorized; httpContext.Request.DetachBlob(memoryBlob); httpContext.Close(); httpContext = null; } else { // Perform Authentication byte[] bytes = null; byte[] decodedOutgoingBlob = null; string outBlob = null; // Find the beginning of the blob. Trust that HTTP.SYS parsed out just our header ok. for (index++; index < authorizationHeader.Length; index++) { if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' && authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n') { break; } } string inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : ""; IPrincipal principal = null; SecurityStatusPal statusCodeNew; ChannelBinding binding; if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Performing Authentication headerScheme: {headerScheme}"); switch (headerScheme) { case AuthenticationSchemes.Negotiate: case AuthenticationSchemes.Ntlm: if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"context: {oldContext} for connectionId: {connectionId}"); string package = headerScheme == AuthenticationSchemes.Ntlm ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Negotiate; if (oldContext != null && oldContext.Package == package) { context = oldContext; } else { binding = GetChannelBinding(connectionId, isSecureConnection, extendedProtectionPolicy); ContextFlagsPal contextFlags = GetContextFlags(extendedProtectionPolicy, isSecureConnection); context = new NTAuthentication(true, package, CredentialCache.DefaultNetworkCredentials, null, contextFlags, binding); } try { bytes = Convert.FromBase64String(inBlob); } catch (FormatException) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"FormatException from FormBase64String"); httpError = HttpStatusCode.BadRequest; error = true; } if (!error) { decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew); if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"GetOutgoingBlob returned IsCompleted: {context.IsCompleted} and statusCodeNew: {statusCodeNew}"); error = !context.IsValidContext; if (error) { // 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 (statusCodeNew.ErrorCode == SecurityStatusPalErrorCode.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0) { statusCodeNew = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidToken); } httpError = HttpStatusFromSecurityStatus(statusCodeNew.ErrorCode); } } if (decodedOutgoingBlob != null) { outBlob = Convert.ToBase64String(decodedOutgoingBlob); } if (!error) { if (context.IsCompleted) { SecurityContextTokenHandle userContext = null; try { if (!CheckSpn(context, isSecureConnection, extendedProtectionPolicy)) { httpError = HttpStatusCode.Unauthorized; } else { httpContext.Request.ServiceName = context.ClientSpecifiedSpn; SafeDeleteContext securityContext = context.GetContext(out statusCodeNew); if (statusCodeNew.ErrorCode != SecurityStatusPalErrorCode.OK) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"HandleAuthentication GetContextToken failed with statusCodeNew: {statusCodeNew}"); } httpError = HttpStatusFromSecurityStatus(statusCodeNew.ErrorCode); } else { SSPIWrapper.QuerySecurityContextToken(GlobalSSPI.SSPIAuth, securityContext, out userContext); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"HandleAuthentication creating new WindowsIdentity from user context: {userContext.DangerousGetHandle().ToString("x8")}"); } WindowsPrincipal windowsPrincipal = new WindowsPrincipal( new WindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName)); principal = windowsPrincipal; // if appropriate, cache this credential on this connection if (UnsafeConnectionNtlmAuthentication && context.ProtocolName == NegotiationInfoClass.NTLM) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"HandleAuthentication inserting principal: {principal} for connectionId: {connectionId}"); } // We may need to call WaitForDisconnect. if (disconnectResult == null) { RegisterForDisconnectNotification(connectionId, ref disconnectResult); } if (disconnectResult != null) { lock ((DisconnectResults as ICollection).SyncRoot) { if (UnsafeConnectionNtlmAuthentication) { disconnectResult.AuthenticatedConnection = windowsPrincipal; } } } else { // Registration failed - UnsafeConnectionNtlmAuthentication ignored. if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"HandleAuthentication RegisterForDisconnectNotification failed."); } } } } } } finally { if (userContext != null) { userContext.Close(); } } } else { // auth incomplete newContext = context; challenge = (headerScheme == AuthenticationSchemes.Ntlm ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Negotiate); if (!String.IsNullOrEmpty(outBlob)) { challenge += " " + outBlob; } } } break; case AuthenticationSchemes.Basic: try { bytes = Convert.FromBase64String(inBlob); inBlob = WebHeaderEncoding.GetString(bytes, 0, bytes.Length); index = inBlob.IndexOf(':'); if (index != -1) { string userName = inBlob.Substring(0, index); string password = inBlob.Substring(index + 1); if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"Basic Identity found, userName: {userName}"); } principal = new GenericPrincipal(new HttpListenerBasicIdentity(userName, password), null); } else { httpError = HttpStatusCode.BadRequest; } } catch (FormatException) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"FromBase64String threw a FormatException."); } } break; } if (principal != null) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"Got principal: {principal}, IdentityName: {principal.Identity.Name} for creating request."); } httpContext.SetIdentity(principal, outBlob); } else { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "Handshake has failed."); } httpContext.Request.DetachBlob(memoryBlob); httpContext.Close(); httpContext = null; } } // if we're not giving a request to the application, we need to send an error ArrayList challenges = null; if (httpContext == null) { // If we already have a challenge, just use it. Otherwise put a challenge for each acceptable scheme. if (challenge != null) { AddChallenge(ref challenges, challenge); } else { // We're starting over. Any context SSPI might have wanted us to keep is useless. if (newContext != null) { if (newContext == context) { context = null; } if (newContext != oldContext) { NTAuthentication toClose = newContext; newContext = null; toClose.CloseContext(); } else { newContext = null; } } // If we're sending something besides 401, do it here. if (httpError != HttpStatusCode.Unauthorized) { if (NetEventSource.IsEnabled) NetEventSource.Info(this, "ConnectionId:" + connectionId + " because of error:" + httpError.ToString()); SendError(requestId, httpError, null); return null; } challenges = BuildChallenge(authenticationScheme, connectionId, out newContext, extendedProtectionPolicy, isSecureConnection); } } // Check if we need to call WaitForDisconnect, because if we do and it fails, we want to send a 500 instead. if (disconnectResult == null && newContext != null) { RegisterForDisconnectNotification(connectionId, ref disconnectResult); // Failed - send 500. if (disconnectResult == null) { if (newContext != null) { if (newContext == context) { context = null; } if (newContext != oldContext) { NTAuthentication toClose = newContext; newContext = null; toClose.CloseContext(); } else { newContext = null; } } if (NetEventSource.IsEnabled) NetEventSource.Info(this, "connectionId:" + connectionId + " because of failed HttpWaitForDisconnect"); SendError(requestId, HttpStatusCode.InternalServerError, null); httpContext.Request.DetachBlob(memoryBlob); httpContext.Close(); return null; } } // Update Session if necessary. if (oldContext != newContext) { if (oldContext == context) { // Prevent the finally from closing this twice. context = null; } NTAuthentication toClose = oldContext; oldContext = newContext; disconnectResult.Session = newContext; if (toClose != null) { toClose.CloseContext(); } } // Send the 401 here. if (httpContext == null) { SendError(requestId, challenges != null && challenges.Count > 0 ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, challenges); if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Scheme:" + authenticationScheme); return null; } if (!stoleBlob) { stoleBlob = true; httpContext.Request.ReleasePins(); } return httpContext; } catch { if (httpContext != null) { httpContext.Request.DetachBlob(memoryBlob); httpContext.Close(); } if (newContext != null) { if (newContext == context) { // Prevent the finally from closing this twice. context = null; } if (newContext != oldContext) { NTAuthentication toClose = newContext; newContext = null; toClose.CloseContext(); } else { newContext = null; } } throw; } finally { try { // Clean up the previous context if necessary. if (oldContext != null && oldContext != newContext) { // Clear out Session if it wasn't already. if (newContext == null && disconnectResult != null) { disconnectResult.Session = null; } oldContext.CloseContext(); } // Delete any context created but not stored. if (context != null && oldContext != context && newContext != context) { context.CloseContext(); } } finally { // Check if the connection got deleted while in this method, and clear out the hashtables if it did. // In a nested finally because if this doesn't happen, we leak. if (disconnectResult != null) { disconnectResult.FinishOwningDisconnectHandling(); } } } }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { if (GlobalLog.IsEnabled) { GlobalLog.Enter("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes"); } var list = new List <SecurityBuffer>(2); if (incomingBlob != null) { list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.Token)); } if (_channelBinding != null) { list.Add(new SecurityBuffer(_channelBinding)); } SecurityBuffer[] inSecurityBufferArray = null; if (list.Count > 0) { inSecurityBufferArray = list.ToArray(); } var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.Token); bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( _credentialsHandle, ref _securityContext, _spn, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { var inSecurityBuffers = new SecurityBuffer[1]; inSecurityBuffers[0] = outSecurityBuffer; statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, inSecurityBuffers); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } outSecurityBuffer.token = null; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, inSecurityBufferArray, outSecurityBuffer, ref _contextFlags); if (GlobalLog.IsEnabled) { GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime && _credentialsHandle != null) { _credentialsHandle.Dispose(); } } if (NegoState.IsError(statusCode)) { CloseContext(); _isCompleted = true; if (throwOnError) { Exception exception = NegotiateStreamPal.CreateExceptionFromError(statusCode); if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception); } throw exception; } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")"); } return(null); } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value will tell us correctly if the handshake is over or not if (statusCode.ErrorCode == SecurityStatusPalErrorCode.OK) { // Success. _isCompleted = true; } else if (GlobalLog.IsEnabled) { // We need to continue. GlobalLog.Print("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode.ErrorCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + LoggingHash.HashString(_securityContext) + "::Handle:" + LoggingHash.ObjectToString(_securityContext) + "]"); } if (GlobalLog.IsEnabled) { GlobalLog.Leave("NTAuthentication#" + LoggingHash.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString()); } return(outSecurityBuffer.token); }
internal SafeDeleteContext GetContext(out SecurityStatusPal status) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.OK); if (!(IsCompleted && IsValidContext)) { NetEventSource.Fail(this, "Should be called only when completed with success, currently is not!"); } if (!IsServer) { NetEventSource.Fail(this, "The method must not be called by the client side!"); } if (!IsValidContext) { status = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidHandle); return null; } return _securityContext; }
private static Interop.SecurityStatus GetInteropFromSecurityStatusPal(SecurityStatusPal status) { switch (status) { case SecurityStatusPal.NotSet: Debug.Fail("SecurityStatus NotSet"); throw new InternalException(); case SecurityStatusPal.OK: return(Interop.SecurityStatus.OK); case SecurityStatusPal.ContinueNeeded: return(Interop.SecurityStatus.ContinueNeeded); case SecurityStatusPal.CompleteNeeded: return(Interop.SecurityStatus.CompleteNeeded); case SecurityStatusPal.CompAndContinue: return(Interop.SecurityStatus.CompAndContinue); case SecurityStatusPal.ContextExpired: return(Interop.SecurityStatus.ContextExpired); case SecurityStatusPal.CredentialsNeeded: return(Interop.SecurityStatus.CredentialsNeeded); case SecurityStatusPal.Renegotiate: return(Interop.SecurityStatus.Renegotiate); case SecurityStatusPal.OutOfMemory: return(Interop.SecurityStatus.OutOfMemory); case SecurityStatusPal.InvalidHandle: return(Interop.SecurityStatus.InvalidHandle); case SecurityStatusPal.Unsupported: return(Interop.SecurityStatus.Unsupported); case SecurityStatusPal.TargetUnknown: return(Interop.SecurityStatus.TargetUnknown); case SecurityStatusPal.InternalError: return(Interop.SecurityStatus.InternalError); case SecurityStatusPal.PackageNotFound: return(Interop.SecurityStatus.PackageNotFound); case SecurityStatusPal.NotOwner: return(Interop.SecurityStatus.NotOwner); case SecurityStatusPal.CannotInstall: return(Interop.SecurityStatus.CannotInstall); case SecurityStatusPal.InvalidToken: return(Interop.SecurityStatus.InvalidToken); case SecurityStatusPal.CannotPack: return(Interop.SecurityStatus.CannotPack); case SecurityStatusPal.QopNotSupported: return(Interop.SecurityStatus.QopNotSupported); case SecurityStatusPal.NoImpersonation: return(Interop.SecurityStatus.NoImpersonation); case SecurityStatusPal.LogonDenied: return(Interop.SecurityStatus.LogonDenied); case SecurityStatusPal.UnknownCredentials: return(Interop.SecurityStatus.UnknownCredentials); case SecurityStatusPal.NoCredentials: return(Interop.SecurityStatus.NoCredentials); case SecurityStatusPal.MessageAltered: return(Interop.SecurityStatus.MessageAltered); case SecurityStatusPal.OutOfSequence: return(Interop.SecurityStatus.OutOfSequence); case SecurityStatusPal.NoAuthenticatingAuthority: return(Interop.SecurityStatus.NoAuthenticatingAuthority); case SecurityStatusPal.IncompleteMessage: return(Interop.SecurityStatus.IncompleteMessage); case SecurityStatusPal.IncompleteCredentials: return(Interop.SecurityStatus.IncompleteCredentials); case SecurityStatusPal.BufferNotEnough: return(Interop.SecurityStatus.BufferNotEnough); case SecurityStatusPal.WrongPrincipal: return(Interop.SecurityStatus.WrongPrincipal); case SecurityStatusPal.TimeSkew: return(Interop.SecurityStatus.TimeSkew); case SecurityStatusPal.UntrustedRoot: return(Interop.SecurityStatus.UntrustedRoot); case SecurityStatusPal.IllegalMessage: return(Interop.SecurityStatus.IllegalMessage); case SecurityStatusPal.CertUnknown: return(Interop.SecurityStatus.CertUnknown); case SecurityStatusPal.CertExpired: return(Interop.SecurityStatus.CertExpired); case SecurityStatusPal.AlgorithmMismatch: return(Interop.SecurityStatus.AlgorithmMismatch); case SecurityStatusPal.SecurityQosFailed: return(Interop.SecurityStatus.SecurityQosFailed); case SecurityStatusPal.SmartcardLogonRequired: return(Interop.SecurityStatus.SmartcardLogonRequired); case SecurityStatusPal.UnsupportedPreauth: return(Interop.SecurityStatus.UnsupportedPreauth); case SecurityStatusPal.BadBinding: return(Interop.SecurityStatus.BadBinding); default: Debug.Fail("Unknown Interop.SecurityStatus value: " + status); throw new InternalException(); } }
// Accepts an incoming binary security blob and returns an outgoing binary security blob. internal byte[]? GetOutgoingBlob(byte[]?incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) { byte[]? result = new byte[_tokenSize]; bool firstTime = _securityContext == null; try { if (!_isServer) { // client session statusCode = NegotiateStreamPal.InitializeSecurityContext( ref _credentialsHandle !, ref _securityContext, _spn, _requestedContextFlags, incomingBlob, _channelBinding, ref result, ref _contextFlags); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"SSPIWrapper.InitializeSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } if (statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { statusCode = NegotiateStreamPal.CompleteAuthToken(ref _securityContext, result); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"SSPIWrapper.CompleteAuthToken() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } result = null; } } else { // Server session. statusCode = NegotiateStreamPal.AcceptSecurityContext( _credentialsHandle, ref _securityContext, _requestedContextFlags, incomingBlob, _channelBinding, ref result, ref _contextFlags); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"SSPIWrapper.AcceptSecurityContext() returns statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode})"); } } } finally { // // Assuming the ISC or ASC has referenced the credential on the first successful call, // we want to decrement the effective ref count by "disposing" it. // The real dispose will happen when the security context is closed. // Note if the first call was not successful the handle is physically destroyed here. // if (firstTime) { _credentialsHandle?.Dispose(); } } if (((int)statusCode.ErrorCode >= (int)SecurityStatusPalErrorCode.OutOfMemory)) { CloseContext(); _isCompleted = true; if (throwOnError) { throw NegotiateStreamPal.CreateExceptionFromError(statusCode); } return(null); } else if (firstTime && _credentialsHandle != null) { // Cache until it is pushed out by newly incoming handles. SSPIHandleCache.CacheCredential(_credentialsHandle); } // The return value will tell us correctly if the handshake is over or not if (statusCode.ErrorCode == SecurityStatusPalErrorCode.OK || (_isServer && statusCode.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded)) { // Success. _isCompleted = true; } else { // We need to continue. if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"need continue statusCode:0x{((int)statusCode.ErrorCode):x8} ({statusCode}) _securityContext:{_securityContext}"); } } return(result); }