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

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

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

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

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

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

  • 我下载了Doug Cook发布的Certificate.cs课程
  • 我使用此代码生成.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步:把它放在一起

  • 我基于这个非常简单的SslStream示例
  • 您将收到有关SslProtocolType枚举的编译时错误。 只需将其从SslProtocolType.Default更改为SslProtocols.Default即可
  • 关于已弃用的function有3个警告。 我用建议的替换品替换了它们。
  • 我使用步骤2中的行替换了Server Program.cs文件中的这一行:

    X509Certificate cert = getServerCert();

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

  • 在Client Program.cs中,CertificateValidationCallback函数失败,因为sslPolicyErrors包含RemoteCertificateChainErrors。 如果深入挖掘,这是因为签署证书的颁发机构不是受信任的根。
  • 我不想让用户将证书导入根存储等,所以我为此做了一个特例,我检查了certificate.GetPublicKeyString()等于我在文件中的公钥对于那台服务器。 如果匹配,我从该函数返回True。 这似乎有效。

第4步:客户端身份validation

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

 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]; } 

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

如果证书未正确生成,则可以获得exception服务器模式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

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

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