private static unsafe void IOCompleted(ListenerClientCertAsyncResult asyncResult, uint errorCode, uint numBytes)
{
HttpListenerRequest httpListenerRequest = (HttpListenerRequest)asyncResult.AsyncObject;
object result = null;
try
{
if (errorCode == Interop.HttpApi.ERROR_MORE_DATA)
{
//There is a bug that has existed in http.sys since w2k3. Bytesreceived will only
//return the size of the inital cert structure. To get the full size,
//we need to add the certificate encoding size as well.
Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = asyncResult.RequestBlob;
asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize);
uint bytesReceived = 0;
errorCode =
Interop.HttpApi.HttpReceiveClientCertificate(
httpListenerRequest.HttpListenerContext.RequestQueueHandle,
httpListenerRequest._connectionId,
(uint)Interop.HttpApi.HTTP_FLAGS.NONE,
asyncResult._memoryBlob,
asyncResult._size,
&bytesReceived,
asyncResult._pOverlapped);
if (errorCode == Interop.HttpApi.ERROR_IO_PENDING ||
(errorCode == Interop.HttpApi.ERROR_SUCCESS && !HttpListener.SkipIOCPCallbackOnSuccess))
{
return;
}
}
if (errorCode != Interop.HttpApi.ERROR_SUCCESS)
{
asyncResult.ErrorCode = (int)errorCode;
result = new HttpListenerException((int)errorCode);
}
else
{
Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = asyncResult._memoryBlob;
if (pClientCertInfo != null)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(null,
$"pClientCertInfo:{(IntPtr)pClientCertInfo} pClientCertInfo->CertFlags: {pClientCertInfo->CertFlags} pClientCertInfo->CertEncodedSize: {pClientCertInfo->CertEncodedSize} pClientCertInfo->pCertEncoded: {(IntPtr)pClientCertInfo->pCertEncoded} pClientCertInfo->Token: {(IntPtr)pClientCertInfo->Token} pClientCertInfo->CertDeniedByMapper: {pClientCertInfo->CertDeniedByMapper}");
}
if (pClientCertInfo->pCertEncoded != null)
{
try
{
byte[] certEncoded = new byte[pClientCertInfo->CertEncodedSize];
Marshal.Copy((IntPtr)pClientCertInfo->pCertEncoded, certEncoded, 0, certEncoded.Length);
result = httpListenerRequest.ClientCertificate = new X509Certificate2(certEncoded);
}
catch (CryptographicException exception)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(null,
$"HttpListenerRequest: {httpListenerRequest} caught CryptographicException: {exception}");
}
result = exception;
}
catch (SecurityException exception)
{
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(null, $"HttpListenerRequest: {httpListenerRequest} caught SecurityException: {exception}");
}
result = exception;
}
}
httpListenerRequest.SetClientCertificateError((int)pClientCertInfo->CertFlags);
}
}
// complete the async IO and invoke the callback
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(null, "Calling Complete()");
}
}
catch (Exception exception) when(!ExceptionCheck.IsFatal(exception))
{
result = exception;
}
finally
{
if (errorCode != Interop.HttpApi.ERROR_IO_PENDING)
{
httpListenerRequest.ClientCertState = ListenerClientCertState.Completed;
}
}
asyncResult.InvokeCallback(result);
}