// 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); }
// 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); }