Beispiel #1
0
    private void Reset(uint size)
    {
        if (size == _size)
        {
            return;
        }
        if (_size != 0)
        {
            _overlapped !.Dispose();
        }
        _size = size;
        if (size == 0)
        {
            _overlapped    = null;
            _memoryBlob    = null;
            _backingBuffer = null;
            return;
        }
        _backingBuffer = new byte[checked ((int)size)];
        var boundHandle = RequestContext.Server.RequestQueue.BoundHandle;

        _overlapped = new SafeNativeOverlapped(boundHandle,
                                               boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer));
        _memoryBlob = (HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO *)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0);
    }
Beispiel #2
0
 private void Dispose(bool disposing)
 {
     if (disposing)
     {
         _cancellationRegistration.Dispose();
         if (_overlapped != null)
         {
             _memoryBlob = null;
             _overlapped.Dispose();
         }
     }
 }
Beispiel #3
0
    // When you use netsh to configure HTTP.SYS with clientcertnegotiation = enable
    // which means negotiate client certificates, when the client makes the
    // initial SSL connection, the server (HTTP.SYS) requests the client certificate.
    //
    // Some apps may not want to negotiate the client cert at the beginning,
    // perhaps serving the default.htm. In this case the HTTP.SYS is configured
    // with clientcertnegotiation = disabled, which 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 certificate at a later time
    // perhaps showing "YOUR ORDERS" page, then the server wants to negotiate
    // Client certs. This will in turn makes HTTP.SYS to do the
    // SEC_I_RENOGOTIATE through which the client cert demand is made
    //
    // NOTE: When calling 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
    internal Task LoadClientCertificateAsync()
    {
        uint size = CertBoblSize;
        bool retry;

        do
        {
            retry = false;
            uint bytesReceived = 0;

            uint statusCode =
                HttpApi.HttpReceiveClientCertificate(
                    RequestQueueHandle,
                    RequestContext.Request.UConnectionId,
                    (uint)HttpApiTypes.HTTP_FLAGS.NONE,
                    RequestBlob,
                    size,
                    &bytesReceived,
                    NativeOverlapped !);

            if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA)
            {
                HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = RequestBlob;
                size = bytesReceived + pClientCertInfo->CertEncodedSize;
                Reset(size);
                retry = true;
            }
            else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND)
            {
                // The client did not send a cert.
                Complete(0, null);
            }
            else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                     HttpSysListener.SkipIOCPCallbackOnSuccess)
            {
                IOCompleted(statusCode, bytesReceived);
            }
            else if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS &&
                     statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING)
            {
                // Some other 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.
                Fail(new HttpSysException((int)statusCode));
            }
        }while (retry);

        return(Task);
    }
Beispiel #4
0
    private static unsafe void IOCompleted(ClientCertLoader asyncResult, uint errorCode, uint numBytes)
    {
        RequestContext requestContext = asyncResult.RequestContext;

        try
        {
            if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA)
            {
                // There is a bug that has existed in http.sys since w2k3.  Bytesreceived will only
                // return the size of the initial cert structure.  To get the full size,
                // we need to add the certificate encoding size as well.

                HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = asyncResult.RequestBlob;
                asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize);

                uint bytesReceived = 0;
                errorCode =
                    HttpApi.HttpReceiveClientCertificate(
                        requestContext.Server.RequestQueue.Handle,
                        requestContext.Request.UConnectionId,
                        (uint)HttpApiTypes.HTTP_FLAGS.NONE,
                        asyncResult._memoryBlob,
                        asyncResult._size,
                        &bytesReceived,
                        asyncResult._overlapped !);

                if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING ||
                    (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && !HttpSysListener.SkipIOCPCallbackOnSuccess))
                {
                    return;
                }
            }

            if (errorCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND)
            {
                // The client did not send a cert.
                asyncResult.Complete(0, null);
            }
            else if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
            {
                asyncResult.Fail(new HttpSysException((int)errorCode));
            }
            else
            {
                HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO *pClientCertInfo = asyncResult._memoryBlob;
                if (pClientCertInfo == null)
                {
                    asyncResult.Complete(0, null);
                }
                else
                {
                    if (pClientCertInfo->pCertEncoded != null)
                    {
                        try
                        {
                            byte[] certEncoded = new byte[pClientCertInfo->CertEncodedSize];
                            Marshal.Copy((IntPtr)pClientCertInfo->pCertEncoded, certEncoded, 0, certEncoded.Length);
                            asyncResult.Complete((int)pClientCertInfo->CertFlags, new X509Certificate2(certEncoded));
                        }
                        catch (CryptographicException exception)
                        {
                            // TODO: Log
                            asyncResult.Fail(exception);
                        }
                        catch (SecurityException exception)
                        {
                            // TODO: Log
                            asyncResult.Fail(exception);
                        }
                    }
                }
            }
        }
        catch (Exception exception)
        {
            asyncResult.Fail(exception);
        }
    }