private SecurityStatusPal GenerateToken(byte[] input, int offset, int count, ref byte[] output)
{
#if TRACE_VERBOSE
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, $"_refreshCredentialNeeded = {_refreshCredentialNeeded}");
#endif
if (offset < 0 || offset > (input == null ? 0 : input.Length))
{
NetEventSource.Fail(this, "Argument 'offset' out of range.");
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (count < 0 || count > (input == null ? 0 : input.Length - offset))
{
NetEventSource.Fail(this, "Argument 'count' out of range.");
throw new ArgumentOutOfRangeException(nameof(count));
}
SecurityBuffer incomingSecurity = null;
SecurityBuffer[] incomingSecurityBuffers = null;
if (input != null)
{
incomingSecurity = new SecurityBuffer(input, offset, count, SecurityBufferType.SECBUFFER_TOKEN);
incomingSecurityBuffers = new SecurityBuffer[]
{
incomingSecurity,
new SecurityBuffer(null, 0, 0, SecurityBufferType.SECBUFFER_EMPTY)
};
}
SecurityBuffer outgoingSecurity = new SecurityBuffer(null, SecurityBufferType.SECBUFFER_TOKEN);
SecurityStatusPal status = default(SecurityStatusPal);
bool cachedCreds = false;
byte[] thumbPrint = null;
//
// Looping through ASC or ISC with potentially cached credential that could have been
// already disposed from a different thread before ISC or ASC dir increment a cred ref count.
//
try
{
do
{
thumbPrint = null;
if (_refreshCredentialNeeded)
{
cachedCreds = _serverMode
? AcquireServerCredentials(ref thumbPrint)
: AcquireClientCredentials(ref thumbPrint);
}
if (_serverMode)
{
status = SslStreamPal.AcceptSecurityContext(
ref _credentialsHandle,
ref _securityContext,
incomingSecurity,
outgoingSecurity,
_remoteCertRequired);
}
else
{
if (incomingSecurity == null)
{
status = SslStreamPal.InitializeSecurityContext(
ref _credentialsHandle,
ref _securityContext,
_destination,
incomingSecurity,
outgoingSecurity);
}
else
{
status = SslStreamPal.InitializeSecurityContext(
_credentialsHandle,
ref _securityContext,
_destination,
incomingSecurityBuffers,
outgoingSecurity);
}
}
} while (cachedCreds && _credentialsHandle == null);
}
finally
{
if (_refreshCredentialNeeded)
{
_refreshCredentialNeeded = false;
//
// Assuming the ISC or ASC has referenced the credential,
// we want to call dispose so to decrement the effective ref count.
//
if (_credentialsHandle != null)
{
_credentialsHandle.Dispose();
}
//
// This call may bump up the credential reference count further.
// Note that thumbPrint is retrieved from a safe cert object that was possible cloned from the user passed cert.
//
if (!cachedCreds && _securityContext != null && !_securityContext.IsInvalid && _credentialsHandle != null && !_credentialsHandle.IsInvalid)
{
SslSessionsCache.CacheCredential(_credentialsHandle, thumbPrint, _sslProtocols, _serverMode, _encryptionPolicy);
}
}
}
output = outgoingSecurity.token;
return status;
}