代码之家  ›  专栏  ›  技术社区  ›  Scott Whitlock

使用SSL和SslStream进行对等身份验证?

  •  17
  • Scott Whitlock  · 技术社区  · 15 年前

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

    this link 显示了一种自动生成自签名证书的方法,因此这是一个开始。

    我已经研究了SslStream的AuthenticateTaserver和AuthenticateTasClient方法。您可以提供回拨以进行验证,因此看起来这是可能的。但现在我已经了解了细节,我真的不认为有可能做到这一点。

    我走的方向对吗?有更好的选择吗?以前有人做过类似的事情吗(基本上是点对点SSL,而不是客户机-服务器)?

    3 回复  |  直到 15 年前
        1
  •  29
  •   Scott Whitlock    10 年前

    步骤1:

    • 我下载了 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个关于不推荐使用的函数的警告。我用建议的替代品全部替换了它们。
    • X509CertificateCert=getServerCert();

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

    • 在Client Program.cs中,CertificateValidationCallback函数失败,因为sslPolicyErrors包含RemoteCertificateChainErrors。如果再深入一点,这是因为签署证书的颁发机构不是受信任的根。
    • 我不想让用户将证书导入根存储等等,所以我为此做了一个特殊的案例,并检查该证书。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与服务器案例中的相同,但请注意AuthenticateClient如何获取证书集合,而不仅仅是一个证书。因此,您必须添加LocalCertificateSelectionCallback,如下所示(在本例中,我只有一个客户端证书,所以我只返回集合中的第一个):

    static X509Certificate CertificateSelectionCallback(object sender,
        string targetHost,
        X509CertificateCollection localCertificates,
        X509Certificate remoteCertificate,
        string[] acceptableIssuers)
    {
        return localCertificates[0];
    }
    
        2
  •  2
  •   mtaskopru    14 年前

    你也可以看看这个例子 示例异步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
  •  1
  •   Dan Breslau    15 年前

    对我来说,你的建议听起来不错,只是听起来你希望等到调用回调后才能生成证书。我不认为那会飞起来;好的,当你调用时,你必须提供一个有效的证书 AuthenticateAsX

    但是,这些类是可重写的;因此,理论上,您可以创建一个派生类,该类首先检查是否需要生成证书,如果需要,则生成证书,然后调用父类 真品茶 方法