System.Net.HttpListenerRequest.ProcessClientCertificate C# (CSharp) Method

ProcessClientCertificate() private method

private ProcessClientCertificate ( ) : void
return void
        private void ProcessClientCertificate()
        {
            if (_clientCertState == ListenerClientCertState.InProgress)
                throw new InvalidOperationException(SR.Format(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()"));
            _clientCertState = ListenerClientCertState.InProgress;
            if (NetEventSource.IsEnabled) NetEventSource.Info(this);
            //--------------------------------------------------------------------
            //When you configure the HTTP.SYS with a flag value 2
            //which means require client certificates, when the client makes the
            //initial SSL connection, server (HTTP.SYS) demands the client certificate
            //
            //Some apps may not want to demand the client cert at the beginning
            //perhaps server the default.htm. In this case the HTTP.SYS is configured
            //with a flag value other than 2, whcih means that the client certificate is
            //optional.So intially when SSL is established HTTP.SYS won't ask for client
            //certificate. This works fine for the default.htm in the case above
            //However, if the app wants to demand a client certficate at a later time
            //perhaps showing "YOUR ORDERS" page, then the server wans to demand
            //Client certs. this will inturn makes HTTP.SYS to do the
            //SEC_I_RENOGOTIATE through which the client cert demand is made
            //
            //THE BUG HERE IS THAT PRIOR TO QFE 4796, we call
            //GET Client certificate native API ONLY WHEN THE HTTP.SYS is configured with
            //flag = 2. Which means that apps using HTTPListener will not be able to
            //demand a client cert at a later point
            //
            //The fix here is to demand the client cert when the channel is NOT INSECURE
            //which means whether the client certs are requried at the beginning or not,
            //if this is an SSL connection, Call HttpReceiveClientCertificate, thus
            //starting the cert negotiation at that point
            //
            //NOTE: WHEN CALLING THE HttpReceiveClientCertificate, you can get
            //ERROR_NOT_FOUND - which means the client did not provide the cert
            //If this is important, the server should respond with 403 forbidden
            //HTTP.SYS will not do this for you automatically ***
            //--------------------------------------------------------------------
            if (_sslStatus != SslStatus.Insecure)
            {
                // at this point we know that DefaultFlags has the 2 bit set (Negotiate Client certificate)
                // the cert, though might or might not be there. try to retrieve it
                // this number is the same that IIS decided to use
                uint size = CertBoblSize;
                while (true)
                {
                    byte[] clientCertInfoBlob = new byte[checked((int)size)];
                    fixed (byte* pClientCertInfoBlob = clientCertInfoBlob)
                    {
                        Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = (Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)pClientCertInfoBlob;

                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Calling Interop.HttpApi.HttpReceiveClientCertificate size:" + size);
                        uint bytesReceived = 0;

                        uint statusCode =
                            Interop.HttpApi.HttpReceiveClientCertificate(
                                HttpListenerContext.RequestQueueHandle,
                                _connectionId,
                                (uint)Interop.HttpApi.HTTP_FLAGS.NONE,
                                pClientCertInfo,
                                size,
                                &bytesReceived,
                                null);

                        if (NetEventSource.IsEnabled) NetEventSource.Info(this,
                            "Call to Interop.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived);
                        if (statusCode == Interop.HttpApi.ERROR_MORE_DATA)
                        {
                            size = bytesReceived + pClientCertInfo->CertEncodedSize;
                            continue;
                        }
                        else if (statusCode == Interop.HttpApi.ERROR_SUCCESS)
                        {
                            if (pClientCertInfo != null)
                            {
                                if (NetEventSource.IsEnabled) NetEventSource.Info(this,
                                    $"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);
                                        _clientCertificate = new X509Certificate2(certEncoded);
                                    }
                                    catch (CryptographicException exception)
                                    {
                                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"CryptographicException={exception}");
                                    }
                                    catch (SecurityException exception)
                                    {
                                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"SecurityException={exception}");
                                    }
                                }
                                _clientCertificateError = (int)pClientCertInfo->CertFlags;
                            }
                        }
                        else
                        {
                            Debug.Assert(statusCode == Interop.HttpApi.ERROR_NOT_FOUND,
                                $"Call to Interop.HttpApi.HttpReceiveClientCertificate() failed with statusCode {statusCode}.");
                        }
                    }
                    break;
                }
            }
            _clientCertState = ListenerClientCertState.Completed;
        }