【问题标题】:Using SSL and SslStream for peer to peer authentication?使用 SSL 和 SslStream 进行对等身份验证?
【发布时间】:2009-03-30 01:56:43
【问题描述】:

我需要在使用 TCP/IP 套接字进行通信的各种进程之间提供安全通信。我想要身份验证和加密。而不是重新发明轮子,我真的很想使用 SSL 和 SslStream 类和自签名证书。我想要做的是根据我本地应用程序中的已知副本验证远程进程的证书。 (不需要证书颁发机构,因为我打算手动复制证书)。

为此,我希望应用程序能够在第一次运行时自动生成新证书。除了 makecert.exe,看起来this link 展示了一种自动生成自签名证书的方法,所以这是一个开始。

我查看了 SslStream 的 AuthenticateAsServer 和 AuthenticateAsClient 方法。您可以提供回调以进行验证,因此看起来是可能的。但是现在我已经了解了它的细节,我真的认为这是不可能的。

我的方向正确吗?有更好的选择吗?以前有没有人做过这样的事情(基本上是点对点 SSL,而不是客户端服务器)?

【问题讨论】:

    标签: c# ssl ssl-certificate sslstream


    【解决方案1】:

    第 1 步:生成自签名证书:

    • 我下载了 Doug Cook 发布的Certificate.cs class
    • 我使用此代码生成 .pfx 证书文件:

      byte[] c = Certificate.CreateSelfSignCertificatePfx(
              "CN=yourhostname.com", //host name
              DateTime.Parse("2000-01-01"), //not valid before
              DateTime.Parse("2010-01-01"), //not valid after
              "mypassword"); //password to encrypt key file
      
          using (BinaryWriter binWriter = new BinaryWriter(
              File.Open(@"testcert.pfx", FileMode.Create)))
          {
              binWriter.Write(c);
          }
      

    第 2 步:加载证书

        X509Certificate cert = new X509Certificate2(
                                @"testcert.pfx", 
                                "mypassword");
    

    第 3 步:组合起来

    • 我基于this very simple SslStream example
    • 您将收到有关 SslProtocolType 枚举的编译时错误。只需将其从 SslProtocolType.Default 更改为 SslProtocols.Default
    • 有 3 条关于已弃用函数的警告。我将它们全部替换为建议的替代品。
    • 我将 Server Program.cs 文件中的这一行替换为第 2 步中的行:

      X509Certificate cert = getServerCert();

    • 在 Client Program.cs 文件中,确保您设置 serverName = yourhostname.com(并且它与证书中的名称匹配)

    • 在客户端 Program.cs 中,CertificateValidationCallback 函数失败,因为 sslPolicyErrors 包含 RemoteCertificateChainErrors。如果再深入一点,这是因为签署证书的颁发机构不是受信任的根。
    • 我不想让用户将证书导入根存储等,所以我为此做了一个特殊情况,我检查了 certificate.GetPublicKeyString() 是否等于我的公钥已为该服务器存档。如果匹配,我从该函数返回 True。这似乎行得通。

    第 4 步: 客户端身份验证

    这是我的客户端的身份验证方式(它与服务器有点不同):

    TcpClient client = new TcpClient();
    client.Connect(hostName, port);
    
    SslStream sslStream = new SslStream(client.GetStream(), false,
        new RemoteCertificateValidationCallback(CertificateValidationCallback),
        new LocalCertificateSelectionCallback(CertificateSelectionCallback));
    
    bool authenticationPassed = true;
    try
    {
        string serverName = System.Environment.MachineName;
    
        X509Certificate cert = GetServerCert(SERVER_CERT_FILENAME, SERVER_CERT_PASSWORD);
        X509CertificateCollection certs = new X509CertificateCollection();
        certs.Add(cert);
    
        sslStream.AuthenticateAsClient(
            serverName,
            certs,
            SslProtocols.Default,
            false); // check cert revokation
    }
    catch (AuthenticationException)
    {
        authenticationPassed = false;
    }
    if (authenticationPassed)
    {
        //do stuff
    }
    

    CertificateValidationCallback 与服务器案例中的相同,但请注意 AuthenticateAsClient 如何获取一组证书,而不仅仅是一个证书。所以,你必须像这样添加一个 LocalCertificateSelectionCallback(在这种情况下,我只有一个客户端证书,所以我只返回集合中的第一个):

    static X509Certificate CertificateSelectionCallback(object sender,
        string targetHost,
        X509CertificateCollection localCertificates,
        X509Certificate remoteCertificate,
        string[] acceptableIssuers)
    {
        return localCertificates[0];
    }
    

    【讨论】:

    • 投反对票,因为您设法链接到一个现已消失的网站。 不要依赖其他网站的链接。 下次在此处发布代码即可。 :(
    • 我不明白...您从哪里获得服务器证书。 X509Certificate cert = GetServerCert(SERVER_CERT_FILENAME, SERVER_CERT_PASSWORD);
    • @pimboden - 它来自第 2 步中链接的代码(可能)
    【解决方案2】:

    你也可以看看这个例子 示例异步 SslStream 客户端/服务器实现 http://blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

    如果证书没有正确生成,你会得到异常服务器模式 SSL 必须使用带有相关私钥的证书。

    基本证书示例

    makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456

    或

    作为外部文件

    makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456 c:\Test.cer

    证书创建工具 (Makecert.exe)
    http://msdn.microsoft.com/en-us/library/bfsktky3%28VS.80%29.aspx

    【讨论】:

      【解决方案3】:

      您的提议对我来说听起来不错,只是听起来您希望等到调用回调以生成证书。我不认为那会飞。 AFAIK,当您调用 AuthenticateAsX 时,您必须提供有效证书。

      但是,这些类是可覆盖的;所以理论上,你可以创建一个派生类,它首先检查是否需要生成证书,如果需要生成它,然后调用父类AuthenticateAsX 方法。

      【讨论】:

      • 对不起,让我澄清一下。当我安装程序时,它第一次运行时会生成一个新证书。服务器将调用 AuthenticateAsServer 并传递此证书,客户端将调用 AuthenticateAsClient 并传递它的证书。但是 SslStream 可能会抛出异常
      • 您期望什么异常,为什么? SSL 堆栈应该可以接受自签名证书(尝试说快五倍 :-)
      • 好吧,我试一试并发布结果。
      猜你喜欢
      • 1970-01-01
      • 2018-12-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      • 1970-01-01
      • 2012-09-12
      • 2017-03-11
      相关资源
      最近更新 更多