public static void BuildChain(
            X509Certificate2 certificate,
            string hostName,
            bool checkCertificateRevocationList,
            out X509Chain chain,
            out SslPolicyErrors sslPolicyErrors)
        {
            chain           = null;
            sslPolicyErrors = SslPolicyErrors.None;

            // Build the chain.
            chain = new X509Chain();
            chain.ChainPolicy.RevocationMode =
                checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
            chain.Build(certificate);
            if (chain.ChainStatus != null && chain.ChainStatus.Length != 0)
            {
                sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
            }

            // Verify the hostName matches the certificate.
            unsafe
            {
                var cppStruct = new Interop.Crypt32.CERT_CHAIN_POLICY_PARA();
                cppStruct.cbSize  = (uint)Marshal.SizeOf <Interop.Crypt32.CERT_CHAIN_POLICY_PARA>();
                cppStruct.dwFlags = 0;

                var eppStruct = new Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA();
                eppStruct.cbSize     = (uint)Marshal.SizeOf <Interop.Crypt32.SSL_EXTRA_CERT_CHAIN_POLICY_PARA>();
                eppStruct.dwAuthType = Interop.Crypt32.AuthType.AUTHTYPE_CLIENT;

                cppStruct.pvExtraPolicyPara = &eppStruct;

                fixed(char *namePtr = hostName)
                {
                    eppStruct.pwszServerName = namePtr;
                    cppStruct.dwFlags        =
                        Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_ALL &
                        ~Interop.Crypt32.CertChainPolicyIgnoreFlags.CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG;

                    var status = new Interop.Crypt32.CERT_CHAIN_POLICY_STATUS();

                    status.cbSize = (uint)Marshal.SizeOf <Interop.Crypt32.CERT_CHAIN_POLICY_STATUS>();
                    if (Interop.Crypt32.CertVerifyCertificateChainPolicy(
                            (IntPtr)Interop.Crypt32.CertChainPolicy.CERT_CHAIN_POLICY_SSL,
                            chain.SafeHandle,
                            ref cppStruct,
                            ref status))
                    {
                        if (status.dwError == Interop.Crypt32.CertChainPolicyErrors.CERT_E_CN_NO_MATCH)
                        {
                            sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                        }
                    }
                    else
                    {
                        // Failure checking the policy. This is a rare error. We will assume the name check failed.
                        // TODO: Log this error.
                        sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNameMismatch;
                    }
                }
            }
        }
Exemple #2
0
        private static void RequestCallback(
            IntPtr handle,
            WinHttpRequestState state,
            uint internetStatus,
            IntPtr statusInformation,
            uint statusInformationLength)
        {
            try
            {
                switch (internetStatus)
                {
                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
                    OnRequestHandleClosing(state);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
                    OnRequestSendRequestComplete(state);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
                    Debug.Assert(statusInformationLength == Marshal.SizeOf <int>());
                    int bytesAvailable = Marshal.ReadInt32(statusInformation);
                    OnRequestDataAvailable(state, bytesAvailable);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
                    OnRequestReadComplete(state, statusInformationLength);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
                    OnRequestWriteComplete(state);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
                    OnRequestReceiveResponseHeadersComplete(state);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REDIRECT:
                    string redirectUriString = Marshal.PtrToStringUni(statusInformation);
                    var    redirectUri       = new Uri(redirectUriString);
                    OnRequestRedirect(state, redirectUri);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
                    OnRequestSendingRequest(state);
                    return;

                case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
                    Debug.Assert(
                        statusInformationLength == Marshal.SizeOf <Interop.WinHttp.WINHTTP_ASYNC_RESULT>(),
                        "RequestCallback: statusInformationLength=" + statusInformationLength +
                        " must be sizeof(WINHTTP_ASYNC_RESULT)=" + Marshal.SizeOf <Interop.WinHttp.WINHTTP_ASYNC_RESULT>());

                    var asyncResult = Marshal.PtrToStructure <Interop.WinHttp.WINHTTP_ASYNC_RESULT>(statusInformation);
                    OnRequestError(state, asyncResult);
                    return;

                default:
                    return;
                }
            }
            catch (Exception ex)
            {
                Interop.WinHttp.WinHttpCloseHandle(handle);
                state.SavedException = ex;
            }
        }