如何在SslStream.AuthenticateAsClient方法中使用证书回调?

时间:2012-09-29 15:15:00

标签: c# ssl certificate x509certificate

当我在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;
        }

如何动态加载证书?

3 个答案:

答案 0 :(得分:4)

基于owlstead的回答,这里是我如何在验证回调中使用单个CA证书和自定义链来避免微软的存储。

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

该功能的名称无关紧要。下面,VerifyServerCertificateRemoteCertificateValidationCallback的回调相同。您也可以将其用于ServerCertificateValidationCallback中的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;
}

答案 1 :(得分:3)

Google快速向我指出了Microsoft SslStream类的一段文字。

  

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

因此,只需实现委托并自行进行验证。

答案 2 :(得分:2)

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

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中安装证书的情况下使用证书作为客户端进行身份验证?