如何在C#中使用HttpWebRequest和SSL证书?

8

我正在编写一个实用程序,它将连接到给定的IP和端口,并使用HttpWebRequest检查SSL证书中的信息。当我尝试提取证书时,我会收到抛出异常的错误。似乎是因为复制SSL证书的行为似乎触发了另一个验证检查。

以下是代码,也许有人可以向我展示更好的方法来完成这项任务,或者告诉我是否遗漏了什么。我不关心SSL证书是否过期或与URL不匹配。对于我的工作来说,这些都不相关。

当我在委托中分配X509Certificate到一个新变量,并在调试器中查看该变量时,所有属性都显示SSLCert.Issuer threw an exception of type 'System.Security.Cryptography.CyrptographicException'

当我尝试访问SSLCert的属性时,我会收到以下异常: m_safeCertContext is an invalid handle

我已经搜索了这个异常,但一切都指向无效的证书,如果证书过期,这可能是真的,并且对于我连接的IP和端口组合也可能是真的。但由于我使用IP连接而不是任何与通用名称匹配的内容,所以我预计会出现这种情况,并且并不在意,因为我仍然需要这些信息。

以下是代码,我还添加了一些注释以说明哪些部分有效和哪些部分无效。

 // To get around the SSL validation in the HttpWebRequest
        System.Net.ServicePointManager.ServerCertificateValidationCallback =
            delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                // The below works but isn't what I want. CertName and ExpireDate are both Strings
                this.CertName = ProcessSubject(certificate.Subject);
                this.ExpireDate = certificate.GetExpirationDateString();
                // The below works but the X509Certificate SSLCert shows exceptions in the debugger for most of the properties.
                this.SSLCert = certificate;

                return true; // **** Always accept
            };
        HttpWebRequest myRequest = (HttpWebRequest)System.Net.WebRequest.Create("https://" + this.IP + ":" + this.Port + "/SSLCheck.html");
        myRequest.KeepAlive = false;
        myRequest.Method = "GET";

        try
        {
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
        }
        catch (Exception e)
        {
            if (e.Message != "The remote server returned an error: (404) Not Found.")
            {
                throw Exception("Error");
            }

        }

        // THE BELOW FAILS
        this.CertName = this.SSLCert.Subject;

这里有很多关于在HttpWebRequest中使用SSL和证书的问题和答案。你看过右边的“相关”问题,或者搜索过[ssl certificate httpwebrequest]吗? - Jim Mischel
1
是的,几乎每个人都在问如何使用客户端证书,但我没有使用它们,或者因为无效证书而在 HttpWebRequest 中遇到错误,但我已经处理了这个问题。 - omniplex
我应该补充一下,大问题在于我想将X509Certificate复制到另一个X509Certificate类型的变量中,但是当我执行“this.SSLCert = certificate;”时,.NET似乎会重新验证证书。 - omniplex
你的示例失败时抛出了什么详细异常?如果可以,请将其添加到您的 OP 中... - Mike Atlas
我添加了更多的信息,包括异常和错误抛出。 - omniplex
这是与您看到的异常相关的内容:http://geekswithblogs.net/timh/archive/2006/04/18/75477.aspx - Mike Atlas
2个回答

1
这只是我的猜测。我认为发生的情况是,在SSL握手中传递的证书信息被.NET用于创建一个证书对象,并在委托中传递给您。委托仅用于验证目的。调用完成后,.NET关闭证书的安全句柄。这就是为什么在回调外部尝试访问证书时调用失败的原因。
为了解决这个问题,您可以在委托内部序列化证书,并在委托外部反序列化它。

谢谢,这对我很有帮助(只需要一个证书属性,所以我将其分配给了从委托中定义的类作用域变量)。 - Alex Filipovici

0

(从我们下面的评论中编辑)

我想你需要做的是创建一个自定义类,并在委托代码内部存储所需的数据,而不是传递实际的证书引用。


不幸的是出现了相同的问题。虽然委托采用X509Certificate类型,但实际传递的类型是X509Certificate2,所以我只需将其转换为实际的类型。虽然我尝试过并进行了再次检查,但仍然存在相同的问题。 - omniplex
也许尝试制作一个成员逐一克隆会更好? - Mike Atlas
这是一个不错的尝试,但奇怪的是,我在MSDN网站上看到该方法是受保护的方法,但由于某种原因它似乎不可用。VS将其标记为错误并且无法编译。此外,智能感知也没有显示它作为有效的方法。 - omniplex
这里有一些有趣的东西。当我在委托中进行赋值时,SSLCert显示正常,但直到我从委托中退出后,它似乎才会内部抛出异常。 - omniplex
这是我的疏忽(MemberwiseClone是受保护的)。我想你需要做的是创建一个自定义类,并在委托内部存储所需的数据,而不是传递实际的证书引用。 - Mike Atlas
好的,至少这让我得到了一些验证,表明我现在所做的方式是最好的(至少目前是这样)。 - omniplex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接