C# Webbrowser:以编程方式定义要使用的证书

C# Webbrowser: Define programatically which certificate to use

我一直致力于连接到服务器的服务,该服务器使用数字签名以经过验证的用户身份访问页面。为了能够连接到网页并使用它,我正在使用 class "WebBrowser" (https://docs.microsoft.com/es-es/dotnet/api/system.windows.forms.webbrowser?view=netcore-3.1)

实际上,当到达该网页时,会弹出此 window 弹出窗口,以选择我在我的 PC 中拥有的可能证书之一来识别我自己:

为了解决这个问题,我一直在网上搜索并找到了不同的潜在解决方案,但其中 none 充分解决了这个问题。

为了能够解决这个问题,我在 class 中包含了下一个代码,这样我就可以捕获来自 WebBrowser 的函数调用:

    [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComImport]
    public interface UCOMIServiceProvider
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int QueryService(
            [In] ref Guid guidService,
            [In] ref Guid riid,
            [Out] out IntPtr ppvObject);
    }
    [ComImport()]
    [ComVisible(true)]
    [Guid("79eac9d5-bafa-11ce-8c82-00aa004ba90b")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IWindowForBindingUI
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetWindow(
            [In] ref Guid rguidReason,
            [In, Out] ref IntPtr phwnd);
    }
    [ComImport()]
    [ComVisible(true)]
    [Guid("79eac9d7-bafa-11ce-8c82-00aa004ba90b")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IHttpSecurity
    {
        //derived from IWindowForBindingUI
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetWindow(
            [In] ref Guid rguidReason,
            [In, Out] ref IntPtr phwnd);
        [PreserveSig]
        int OnSecurityProblem(
            [In, MarshalAs(UnmanagedType.U4)] uint dwProblem);
    }

以及能够知道何时出现问题并尝试解决问题的功能:

            public int OnSecurityProblem(uint dwProblem)
            {
                int dwCertSelection2 = 2;
                IntPtr dwCertSelection = new IntPtr(dwCertSelection2);
                //ignore errors
                //undocumented return code, does not work on IE6
                if (dwProblem == 12044)
                {

                    X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
                    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

                    X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
                    X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
                    X509Certificate2 x509 = fcollection[2];

                    IntPtr unmanagedPointer = Marshal.AllocHGlobal(x509.RawData.Length);
                    Marshal.Copy(x509.RawData, 0, unmanagedPointer, x509.RawData.Length);

                    bool VF_Resultado = WinHttpSetOption(this.myWebBrowser.Handle, 47, unmanagedPointer, x509.RawData.Length);
                    Marshal.FreeHGlobal(unmanagedPointer);
                    store.Close();
                    return RPC_E_RETRY;
                }

                return S_OK;
            }

为了进一步说明:

if (dwProblem == 12044) --> //12044, ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED。表示我们需要通过认证

bool VF_Resultado = WinHttpSetOption(this.myWebBrowser.Handle, 47, unmanagedPointer, x509.RawData.Length); --> //INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT 47、理论上有了这个功能我们就可以不用选择就可以指明我们要使用的certify。

此代码基于不同的来源(我尝试了两种解决方案,但没有成功):

https://docs.microsoft.com/en-us/windows/win32/winhttp/ssl-in-winhttp

https://www.codeguru.com/cpp/i-n/internet/generalinternet/article.php/c3367/Selecting-a-client-certificate.htm

问题是此代码没有按预期执行,我有各种疑问以确保它能正常工作:

  1. 我应该使用 WinHTTP、wininet 还是其他库?
  2. 调用函数 WinHttpSetOption 或 InternetSetOption 时,句柄(函数的第一个参数)应该是什么?
  3. 我应该如何传递X509证书以确保WebBrowser理解并使用它?我使用的代码来自 C++,我不知道我是否正确移植了数据,实际上我发送的是原始数据。

谢谢

经过多次测试和审查,我得出结论,使用webBrowser控件是不可能做到这一点的,这是因为必须使用此功能才能通过认证:

WinHttpSetOption(this.myWebBrowser.Handle, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, dwCertSelection, size)

这里的主要问题是 WinHttpSetOption 需要调用函数后返回的处理程序会话 "HttpOpenRequest":

https://docs.microsoft.com/en-us/windows/win32/winhttp/hinternet-handles-in-winhttp#handle-hierarchy

无法从 C# WebBrowser 对象获取的数据。