C# 使用 SSL 和 SslStream 进行对等身份验证?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/695802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using SSL and SslStream for peer to peer authentication?
提问by Scott Whitlock
I need to provide secure communication between various processes that are using TCP/IP sockets for communication. I want both authentication and encryption. Rather than re-invent the wheel I would really like to use SSL and the SslStream class and self-signed certificates. What I want to do is validate the remote process's certificate against a known copy in my local application. (There doesn't need to be a certificate authority because I intend for the certificates to be copied around manually).
我需要在使用 TCP/IP 套接字进行通信的各种进程之间提供安全通信。我想要身份验证和加密。而不是重新发明轮子,我真的很想使用 SSL 和 SslStream 类以及自签名证书。我想要做的是根据本地应用程序中的已知副本验证远程进程的证书。(不需要证书颁发机构,因为我打算手动复制证书)。
To do this, I want the application to be able to automatically generate a new certifiate the first time it is run. In addition to makecert.exe, it looks like this linkshows a way to automatically generate self-signed certificates, so that's a start.
为此,我希望应用程序能够在第一次运行时自动生成新的证书。除了 makecert.exe 之外,这个链接似乎显示了一种自动生成自签名证书的方法,所以这是一个开始。
I've looked at the AuthenticateAsServer and AuthenticateAsClient methods of SslStream. You can provide call-backs for verification, so it looks like it's possible. But now that I'm into the details of it, I really don't think it's possible to do this.
我查看了 SslStream 的 AuthenticateAsServer 和 AuthenticateAsClient 方法。您可以提供回调以进行验证,因此看起来是可能的。但是现在我已经了解了它的细节,我真的认为这是不可能的。
Am I going in the right direction? Is there a better alternative? Has anyone done anything like this before (basically peer-to-peer SSL rather than client-server)?
我是否朝着正确的方向前进?有更好的选择吗?以前有没有人做过这样的事情(基本上是对等 SSL 而不是客户端 - 服务器)?
采纳答案by Scott Whitlock
Step 1:Generating a self-signed certificate:
第 1 步:生成自签名证书:
- I downloaded the Certificate.cs classposted by Doug Cook
I used this code to generate a .pfx certificate file:
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); }
- 我下载了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); }
Step 2:Loading the certificate
第二步:加载证书
X509Certificate cert = new X509Certificate2(
@"testcert.pfx",
"mypassword");
Step 3:Putting it together
第 3 步:把它放在一起
- I based it on this very simple SslStream example
- You will get a compile time error about the SslProtocolType enumeration. Just change that from SslProtocolType.Default to SslProtocols.Default
- There were 3 warnings about deprecated functions. I replaced them all with the suggested replacements.
I replaced this line in the Server Program.cs file with the line from Step 2:
X509Certificate cert = getServerCert();
In the Client Program.cs file, make sure you set serverName = yourhostname.com (and that it matches the name in the certificate)
- In the Client Program.cs, the CertificateValidationCallback function fails because sslPolicyErrors contains a RemoteCertificateChainErrors. If you dig a little deeper, this is because the issuing authority that signed the certificate is not a trusted root.
- I don`t want to get into having the user import certificates into the root store, etc., so I made a special case for this, and I check that certificate.GetPublicKeyString() is equal to the public key that I have on file for that server. If it matches, I return True from that function. That seems to work.
- 我基于这个非常简单的 SslStream 示例
- 您将收到有关 SslProtocolType 枚举的编译时错误。只需将其从 SslProtocolType.Default 更改为 SslProtocols.Default
- 有 3 个关于不推荐使用的函数的警告。我用建议的替代品替换了它们。
我用步骤 2 中的行替换了 Server Program.cs 文件中的这一行:
X509Certificate cert = getServerCert();
在 Client Program.cs 文件中,确保设置 serverName = yourhostname.com(并且它与证书中的名称匹配)
- 在 Client Program.cs 中,CertificateValidationCallback 函数失败,因为 sslPolicyErrors 包含 RemoteCertificateChainErrors。如果你再深入一点,这是因为签署证书的颁发机构不是受信任的根。
- 我不想让用户将证书导入根存储等,所以我为此做了一个特例,并检查了 certificate.GetPublicKeyString() 是否等于我存档的公钥对于那个服务器。如果匹配,我从该函数返回 True。这似乎有效。
Step 4:Client Authentication
第 4 步:客户端身份验证
Here's how my client authenticates (it's a little different than the server):
这是我的客户端进行身份验证的方式(与服务器略有不同):
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
}
The CertificateValidationCallback is the same as in the server case, but note how AuthenticateAsClient takes a collection of certificates, not just one certificate. So, you have to add a LocalCertificateSelectionCallback, like this (in this case, I only have one client cert so I just return the first one in the collection):
CertificateValidationCallback 与服务器案例中的相同,但请注意 AuthenticateAsClient 如何获取一组证书,而不仅仅是一个证书。所以,你必须像这样添加一个 LocalCertificateSelectionCallback(在这种情况下,我只有一个客户端证书,所以我只返回集合中的第一个):
static X509Certificate CertificateSelectionCallback(object sender,
string targetHost,
X509CertificateCollection localCertificates,
X509Certificate remoteCertificate,
string[] acceptableIssuers)
{
return localCertificates[0];
}
回答by Dan Breslau
What you're proposing sounds fine to me, except that it sounds like you're looking to wait until the callback is invoked in order to generate the certificate. I don't think that that will fly; AFAIK, you've got to provide a valid certificate when you invoke AuthenticateAsX
.
您提出的建议对我来说听起来不错,只是听起来您希望等到调用回调以生成证书。我不认为那会飞;AFAIK,您必须在调用AuthenticateAsX
.
However, these classes are overridable; so in theory, you could create a derived class which first checks to see if a certificate needs to be generated, generates it if need be, then invokes the parent AuthenticateAsX
method.
但是,这些类是可覆盖的;所以理论上,您可以创建一个派生类,它首先检查是否需要生成证书,如果需要则生成它,然后调用父AuthenticateAsX
方法。
回答by mtaskopru
you can look too this example Sample Asynchronous SslStream Client/Server Implementation http://blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx
你也可以看看这个例子Sample Asynchronous SslStream Client/Server Implementation http://blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx
if certificate is not produced correctly you can get exception The server mode SSL must use a certificate with the associated private key.
如果证书未正确生成,您可能会遇到异常 服务器模式 SSL 必须使用具有关联私钥的证书。
basic certificate example
基本证书示例
makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456
makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456
or
或者
as external file
作为外部文件
makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456 c:\Test.cer
makecert -sr LocalMachine -ss My -n CN=Test -sky exchange -sk 123456 c:\Test.cer
Certificate Creation Tool (Makecert.exe)
http://msdn.microsoft.com/en-us/library/bfsktky3%28VS.80%29.aspx
证书创建工具 (Makecert.exe)
http://msdn.microsoft.com/en-us/library/bfsktky3%28VS.80%29.aspx