internal ChannelBinding GetChannelBindingFromTls(ulong connectionId)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, $"connectionId: {connectionId}");
// +128 since a CBT is usually <128 thus we need to call HRCC just once. If the CBT
// is >128 we will get ERROR_MORE_DATA and call again
int size = s_requestChannelBindStatusSize + 128;
Debug.Assert(size >= 0);
byte[] blob = null;
Interop.HttpApi.SafeLocalFreeChannelBinding token = null;
uint bytesReceived = 0;
uint statusCode;
do
{
blob = new byte[size];
fixed (byte* blobPtr = blob)
{
// Http.sys team: ServiceName will always be null if
// HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set.
statusCode = Interop.HttpApi.HttpReceiveClientCertificate(
RequestQueueHandle,
connectionId,
(uint)Interop.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN,
blobPtr,
(uint)size,
&bytesReceived,
null);
if (statusCode == Interop.HttpApi.ERROR_SUCCESS)
{
int tokenOffset = GetTokenOffsetFromBlob((IntPtr)blobPtr);
int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr);
Debug.Assert(tokenSize < Int32.MaxValue);
token = Interop.HttpApi.SafeLocalFreeChannelBinding.LocalAlloc(tokenSize);
if (token.IsInvalid)
{
throw new OutOfMemoryException();
}
Marshal.Copy(blob, tokenOffset, token.DangerousGetHandle(), tokenSize);
}
else if (statusCode == Interop.HttpApi.ERROR_MORE_DATA)
{
int tokenSize = GetTokenSizeFromBlob((IntPtr)blobPtr);
Debug.Assert(tokenSize < Int32.MaxValue);
size = s_requestChannelBindStatusSize + tokenSize;
}
else if (statusCode == Interop.HttpApi.ERROR_INVALID_PARAMETER)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Error(this, SR.net_ssp_dont_support_cbt);
}
return null; // old schannel library which doesn't support CBT
}
else
{
throw new HttpListenerException((int)statusCode);
}
}
} while (statusCode != Interop.HttpApi.ERROR_SUCCESS);
return token;
}