3

当我在 IE(工具/Internet 选项/内容/证书)中手动导入证书时,我的 C#.NET SSL 连接有效,但是如何通过代码加载证书?这是我的代码:

TcpClient client = new TcpClient(ConfigManager.SSLSwitchIP, Convert.ToInt32(ConfigManager.SSLSwitchPort));

SslStream sslStream = new SslStream(
                client.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),
                null
                );
sslStream.AuthenticateAsClient("Test");

如果我在 Internet Explorer 中手动导入我的证书文件,上面的代码可以正常工作。但是,如果我从 IE 中删除我的证书并改用以下代码,我会得到身份验证异常:

sslStream.AuthenticateAsClient("Test", GetX509CertificateCollection(), SslProtocols.Default, false);

这是'GetX509CertificateCollection'方法:

public static X509CertificateCollection GetX509CertificateCollection()
        {
            X509Certificate2 certificate1 = new X509Certificate2("c:\\ssl.txt");
            X509CertificateCollection collection1 = new X509CertificateCollection();
            collection1.Add(certificate1);
            return collection1;
        }

我应该怎么做才能动态加载我的证书?

4

3 回答 3

5

为了建立 owlstead 的答案,以下是我如何在验证回调中使用单个 CA 证书和自定义链来避免 Microsoft 的商店。

我还没有弄清楚如何chain2默认使用这个链(下面),这样就不需要回调了。也就是说,将它安装在 ssl 套接字上,连接将“正常工作”。而且我还没有弄清楚如何安装它以便将其传递给回调。也就是说,我必须为回调的每次调用构建链。我认为这些是 .Net 中的架构缺陷,但我可能会遗漏一些明显的东西。

函数的名称无关紧要。下面,VerifyServerCertificate是与 相同的回调RemoteCertificateValidationCallback。您也可以将它用于ServerCertificateValidationCallbackin ServicePointManager

static bool VerifyServerCertificate(object sender, X509Certificate certificate,
    X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    try
    {
        String CA_FILE = "ca-cert.der";
        X509Certificate2 ca = new X509Certificate2(CA_FILE);

        X509Chain chain2 = new X509Chain();
        chain2.ChainPolicy.ExtraStore.Add(ca);

        // Check all properties
        chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

        // This setup does not have revocation information
        chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

        // Build the chain
        chain2.Build(new X509Certificate2(certificate));

        // Are there any failures from building the chain?
        if (chain2.ChainStatus.Length == 0)
            return true;

        // If there is a status, verify the status is NoError
        bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError;
        Debug.Assert(result == true);

        return result;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }

    return false;
}
于 2014-03-28T00:31:14.243 回答
3

SslStream一个快速的谷歌向我指出了微软课堂上的一段文字。

身份验证由安全支持提供程序 (SSPI) 通道提供程序处理。客户端有机会通过 RemoteCertificateValidationCallback在创建 SslStream 时指定委托来控制服务器证书的验证。服务器还可以通过提供 RemoteCertificateValidationCallback委托来控制验证。委托引用的方法包括远程方的证书和 SSPI 在验证证书时遇到的任何错误。请注意,如果服务器指定了委托,则无论服务器是否请求客户端身份验证,都会调用委托的方法。如果服务器没有请求客户端身份验证,则服务器的委托方法会收到一个空证书和一个空的证书错误数组。

所以只需实现委托并自己进行验证。

于 2012-10-08T19:29:30.533 回答
2

在尝试通过 SSLStream 对象作为客户端进行身份验证之前,我编写了另一种方法来将我的证书添加到受信任的根证书颁发机构(根):

public static void InstallCertificate()
    {
        X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadWrite);
        string fileName = "sslcert.pem";
        X509Certificate2 certificate1;
        try
        {
            certificate1 = new X509Certificate2(fileName);
        }
        catch (Exception ex)
        {
            throw new Exception("Error loading SSL certificate file." + Environment.NewLine + fileName);
        }

        store.Add(certificate1);
        store.Close();
    }

接着:

InstallCertificate();
sslStream.AuthenticateAsClient("Test");

它工作正常,没有任何警告或错误。但基本问题仍未解决:

如何使用证书作为客户端进行身份验证而不将其安装在 Windows 中?

于 2012-10-01T06:38:31.183 回答