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 (((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;
}
}