Exemplo n.º 1
0
 // Will be called from the base class upon InvokeCallback()
 protected override void Cleanup()
 {
     if (_pOverlapped != null)
     {
         _memoryBlob = null;
         _boundHandle.FreeNativeOverlapped(_pOverlapped);
         _pOverlapped = null;
         _boundHandle = null;
     }
     GC.SuppressFinalize(this);
     base.Cleanup();
 }
Exemplo n.º 2
0
 internal void Reset(uint size)
 {
     if (size == _size)
     {
         return;
     }
     if (_size != 0)
     {
         _boundHandle.FreeNativeOverlapped(_pOverlapped);
     }
     _size = size;
     if (size == 0)
     {
         _pOverlapped   = null;
         _memoryBlob    = null;
         _backingBuffer = null;
         return;
     }
     _backingBuffer = new byte[checked ((int)size)];
     _pOverlapped   = _boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: _backingBuffer);
     _memoryBlob    = (Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0);
 }
 internal void Reset(uint size)
 {
     if (size == _size)
     {
         return;
     }
     if (_size != 0)
     {
         _boundHandle.FreeNativeOverlapped(_pOverlapped);
     }
     _size = size;
     if (size == 0)
     {
         _pOverlapped = null;
         _memoryBlob = null;
         _backingBuffer = null;
         return;
     }
     _backingBuffer = new byte[checked((int)size)];
     _pOverlapped = _boundHandle.AllocateNativeOverlapped(s_IOCallback, state: this, pinData: _backingBuffer);
     _memoryBlob = (Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0);
 }
Exemplo n.º 4
0
        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 initially 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[0])
                    {
                        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;
        }
Exemplo n.º 5
0
        private ListenerClientCertAsyncResult AsyncProcessClientCertificate(AsyncCallback requestCallback, object state)
        {
            if (_clientCertState == ListenerClientCertState.InProgress)
            {
                throw new InvalidOperationException(SR.Format(SR.net_listener_callinprogress, "GetClientCertificate()/BeginGetClientCertificate()"));
            }
            _clientCertState = ListenerClientCertState.InProgress;

            ListenerClientCertAsyncResult asyncResult = null;

            //--------------------------------------------------------------------
            //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 initially 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;
                asyncResult = new ListenerClientCertAsyncResult(HttpListenerContext.RequestQueueBoundHandle, this, state, requestCallback, size);
                try
                {
                    while (true)
                    {
                        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,
                                asyncResult.RequestBlob,
                                size,
                                &bytesReceived,
                                asyncResult.NativeOverlapped);

                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveClientCertificate returned:" + statusCode + " bytesReceived:" + bytesReceived);
                        }
                        if (statusCode == Interop.HttpApi.ERROR_MORE_DATA)
                        {
                            Interop.HttpApi.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = asyncResult.RequestBlob;
                            size = bytesReceived + pClientCertInfo->CertEncodedSize;
                            asyncResult.Reset(size);
                            continue;
                        }
                        if (statusCode != Interop.HttpApi.ERROR_SUCCESS &&
                            statusCode != Interop.HttpApi.ERROR_IO_PENDING)
                        {
                            // someother bad error, possible return values are:
                            // ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED
                            // Also ERROR_BAD_DATA if we got it twice or it reported smaller size buffer required.
                            throw new HttpListenerException((int)statusCode);
                        }

                        if (statusCode == Interop.HttpApi.ERROR_SUCCESS &&
                            HttpListener.SkipIOCPCallbackOnSuccess)
                        {
                            asyncResult.IOCompleted(statusCode, bytesReceived);
                        }
                        break;
                    }
                }
                catch
                {
                    asyncResult?.InternalCleanup();
                    throw;
                }
            }
            else
            {
                asyncResult = new ListenerClientCertAsyncResult(HttpListenerContext.RequestQueueBoundHandle, this, state, requestCallback, 0);
                asyncResult.InvokeCallback();
            }
            return(asyncResult);
        }
Exemplo n.º 6
0
        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);
        }
 // Will be called from the base class upon InvokeCallback()
 protected override void Cleanup()
 {
     if (_pOverlapped != null)
     {
         _memoryBlob = null;
         _boundHandle.FreeNativeOverlapped(_pOverlapped);
         _pOverlapped = null;
         _boundHandle = null;
     }
     GC.SuppressFinalize(this);
     base.Cleanup();
 }