第 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
- 有 3 条关于已弃用功能的警告。我用建议的替代品替换了它们。
我将 Server Program.cs 文件中的这一行替换为步骤 2 中的行:
X509Certificate 证书 = getServerCert();
在 Client Program.cs 文件中,确保您设置 serverName = yourhostname.com(并且它与证书中的名称匹配)
- 在 Client 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];
}