SSLStream示例 – 如何获取有效的证书?

我在这里使用msdn的SSLStream示例。 客户端代码“似乎”工作正常,因为我可以连接到谷歌,它至少得到过去的身份validation,但服务器没有。

从msdn页面的评论中,我使用此页面上的过程生成我自己的私钥,但它不起作用。 我得到System.NotSupportedException: The server mode SSL must use a certificate with the associated private key.的exceptionSystem.NotSupportedException: The server mode SSL must use a certificate with the associated private key. 所以我很确定我所做的一切都是错的。

所以我的问题很简单:如何从msdn获取/生成适用于我自己的小示例程序的密钥? 无论如何,它都可以是自签名的,但我对SSL来说太新了,甚至不知道我到底需要什么。 我想要做的就是运行as-given示例,除了为我的本地服务器指定自己的证书。 如果我只是想在他们两个之间进行通信,那么知道我必须在我的第二台机器上安装什么是很好的(所以它不是100%本地主机的例子)。

我个人认为这是示例文档中的一个缺陷。 它应该说“要运行它,你需要做A,B,C等”,但事实并非如此。

即使使用自签名证书,您也可以使用该示例。 我已经从你正在使用的makecert教程中提取了一些命令,只做了一些修改:

 makecert -sv RootCATest.pvk -r -n "CN=FakeServerName" RootCATest.cer makecert -ic RootCATest.cer -iv RootCATest.pvk -n "CN=FakeServerName" -sv TempCert.pvk -pe -sky exchange TempCert.cer cert2spc TempCert.cer TempCert.spc pvkimprt -pfx TempCert.spc TempCert.pvk 

可以在Microsoft SDKs\Window\v7.0A\Bin文件夹中找到makecertcert2psc 。 可以在此处下载pvkImport.exe安装程序(由@Jospeph提供并经过VirusTotalvalidation) 。 这曾经可以从微软网站下载,但他们已经把它删除了。

对于下一步,请确保在pvkimprt的对话框出现时选择导出私钥

 pvkimprt -pfx TempCert.spc TempCert.pvk 

在此处输入图像描述

当您选择包含私钥时, pvkimprt将提示您输入密码。 将生成的.pfx文件导入服务器计算机的个人存储区时,需要稍后提供此密码

在此处输入图像描述

接下来,将RootCATest.cer导入Computer商店的受信任的根证书颁发机构(在服务器和客户端上)。 请注意,证书颁发给FakeServerName 。 这必须与SslTcpClient期望的服务器名称匹配: sslStream.AuthenticateAsClient(serverName) ,其中serverName是传递给SslTcpClient.exe的第二个参数的值。

当您的客户端连接时,服务器会提供一个证书,告诉客户端“我是FakeServerName”。 如果客户端计算机信任颁发证书的CA,则客户端将接受此声明,这通过将RootCATest.cer导入客户端的受信任的根证书颁发机构来实现。

最后,您需要将服务器将要使用的私钥导入服务器计算机的个人存储中。 此步骤很重要,因为它解决了The server mode SSL must use a certificate with the associated private key. 。 这是通过导入先前生成的.pfx文件来实现的。 确保将文件类型filter更改为“所有文件”,以便您可以看到生成的.pfx文件:

在此处输入图像描述

MSDN提供的示例代码使用端口443(这是标准的ssl端口)。 自从我创建了控制台应用程序以来,我将示例类使用的端口更改为8080:

SslTcpServer:

 TcpListener listener = new TcpListener(IPAddress.Any, 8080); 

SslTcpClient:

 TcpClient client = new TcpClient(machineName, 8080); 

这是输出:

在此处输入图像描述

你会像这样启动你的服务器:

 SslTcpServer.exe TempCert.cer 

从客户端,你会这样连接:

 SslTcpClient.exe  FakeServerName 

使用此命令生成证书:

 makecert -r -pe -n "CN=localhost" -m 12 -sky CertSubject -ss my serverCert.cer 

然后从客户端连接到这样的服务器(假设我们使用你提到的MSDN示例):

 SslTcpClient.RunClient ("localhost", "CertSubject"); 

您将在ValidateServerCertificate()调用中获得validation错误 – 但这是预期的 – 您使用的是自签名证书。 只要在那里回归真实。

更新:

我不同意董建议将自签名证书添加到客户的受信任的根证书颁发机构的建议。 如果您计划分发/支持您的软件,我认为以后可能会导致问题。 例如,客户端可能会重新安装Windows,或者将他的个人资料移动到另一台PC,或者其他什么 – 并且理解为什么你的软件突然停止工作会很痛苦(再次,我说的是长期 – 从现在起一两年,当时你完全忘记了这个小小的“诡计”)。

相反,我宁愿建议将您的证书“硬编码”(通过比较主题和指纹)到客户端的逻辑中,如下所示:

 X509Certificate2 certificate = (X509Certificate2)cert; if (certificate.Subject.StartsWith("CN=FAKE_SERVER_WHATEVER") && !string.IsNullOrEmpty(certificate.Thumbprint) && certificate.Thumbprint.ToLower() == "11c4446c572a9918ced3618728b91b3a07982787") { return true; } return false; 

由于下载pvkimprt的Microsoft 链接已损坏,而且我是OpenSSL的粉丝,我在OpenSSL中留下了两个解决方案。

VARIANT#1 – 自签名证书

首先,您需要下载OpenSSL和此配置文件 。 @Tung说你可以使用完美的自签名证书。 将下载的配置文件复制到运行OpenSSL命令的同一文件夹中。

让我们生成私钥和证书颁发机构的证书:

 openssl req -x509 -config openssl.cnf -newkey rsa:4096 -sha256 -out ssl-cacert.pem -keyout ssl-cakey.pem -outform PEM 

*使用-nodes参数省略密码,但出于安全原因,我不建议使用它。

如果您希望检查CA证书的信息,请执行以下命令:

 openssl x509 -purpose -in ssl-cacert.pem -inform PEM 

让我们创建证书请求,必须使用机器名设置Common Name

 openssl req -config openssl.cnf -newkey rsa:2048 -keyout ssl-serverkey.pem -sha256 -out ssl-server.csr -outform PEM 

* -nodes参数的相同注释。

如果要检查证书请求信息,请执行以下命令:

 openssl req -text -noout -verify -in ssl-server.csr 

使用生成的CA证书对证书请求进行签名:

 openssl x509 -req -days 365 -CA ssl-cacert.pem -CAkey ssl-cakey.pem -CAcreateserial -in ssl-server.csr -out ssl-server-certificate.pem 

让我们用PFX格式制作自签名证书:

 openssl pkcs12 -export -out ssl-certificate.pfx -inkey ssl-serverkey.pem -in ssl-server-certificate.pem -certfile ssl-cacert.pem -name "SSL Self Signed Certificate" 

现在您应该导入.pfx证书。

  1. 双击ssl-certificate.pfx文件。
  2. 选择“本地计算机”选项和下一步。
  3. 输入密码,然后选中“将此密钥标记为可导出”复选框
  4. 选择单选按钮“将所有证书放在以下存储中”
  5. 选择个人存储,然后单击下一步。

有了这个步骤必须工作。

VARIANT#2 – 生成CA证书和服务器证书

我个人比第一个更喜欢这个解决方案,因为只有我必须将根CA证书分发给客户端。

首先下载此配置文件。

我们将使用相应的私钥生成根CA证书:

 openssl req -x509 -config openssl.cnf -newkey rsa:4096 -sha256 -keyout ssl-cakey.pem -out ssl-cacert.pem -outform PEM 

让我们检查证书属性:

 openssl x509 -purpose -in ssl-cacert.pem -inform PEM 

必须显示的信息应如下所示:

 Certificate purposes: SSL client : No SSL client CA : Yes SSL server : No SSL server CA : Yes Netscape SSL server : No Netscape SSL server CA : Yes S/MIME signing : No S/MIME signing CA : Yes S/MIME encryption : No S/MIME encryption CA : Yes CRL signing : Yes CRL signing CA : Yes Any Purpose : Yes Any Purpose CA : Yes OCSP helper : Yes OCSP helper CA : Yes Time Stamp signing : No Time Stamp signing CA : Yes -----BEGIN CERTIFICATE----- MIIGLjCCBBagAwIBAgIJANCzs7UBFJMpMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNV ... im1yDnB5nPwkPwZ9eRmlzIc6OaLZcfbFfSeSw8/ipKZcEJ1u+EFrB0JhuSbeLXtQ N/8= -----END CERTIFICATE----- 

使用以下命令创建证书请求:

 openssl req -config openssl.cnf -newkey rsa:2048 -sha256 -keyout ssl-serverkey.pem -out ssl-servercert.csr -outform PEM 

将Common Name设置为服务器的机器名称非常重要。

validation此证书请求的信息:

 openssl req -text -noout -verify -in ssl-servercert.csr 

信息显示必须具有以下格式,检查Subject中的CN字段是否为服务器计算机的名称。

 verify OK Certificate Request: Data: Version: 0 (0x0) Subject: C=US, ST=..., L=..., O=..., OU=..., CN=SERVERNAME Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:aa:92:bd:87:75:18:6c:c0:23:3f:0b:5a:46:1a: ... fe:13 Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Key Identifier: 7E:7D:79:F4:CD:71:0E:90:3A:9A:F8:3F:83:7D:89:90:4D:D4:F0:12 X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature, Key Encipherment, Data Encipherment Signature Algorithm: sha256WithRSAEncryption 34:e1:b4:db:b2:87:cc:11:3e:85:3c:ed:ac:8d:d9:43:ae:b0: ... 56:84:29:f9 

创建证书文件夹:

 mkdir certificates 

创建数据库索引文件:

Windows: type NUL > index.txt
Unix: touch index.txt

创建serial.txt文件,其中存储当前序列号:

 echo '01' > serial.txt 

使用该命令创建签署证书请求2年的服务器证书。 根据您是否使用-nodes参数,系统将提示您输入CA证书的密码短语:

 openssl ca -config openssl.cnf -days 730 -policy signing_policy -extensions v3_req -out ssl-servercert.pem -infiles ssl-servercert.csr 

然后显示格式为的文本:

 Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :ASN.1 12:'...' localityName :ASN.1 12:'...' organizationName :ASN.1 12:'...' organizationalUnitName:ASN.1 12:'...' commonName :ASN.1 12:'SERVERNAME' Certificate is to be certified until Jul 4 23:26:59 2018 GMT (730 days) Sign the certificate? [y/n]: 

选择y并将提示以下文本,再次选择y

 1 out of 1 certificate requests certified, commit? [y/n] 

将生成的证书导出为PFX格式:

 openssl pkcs12 -export -out ssl-certificate.pfx -inkey ssl-serverkey.pem -in ssl-servercert.pem -name "SSL Signed Certificate" 

您将需要执行以下步骤以启用SSL而不会出现问题:

在服务器上:

  • 在“受信任的根证书颁发机构”存储上导入根CA证书( ssl-cacert.pem文件),选择“计算机帐户”。
  • 在个人存储上选择计算机帐户导入SSL的SSL服务器证书( ssl-certificate.pfx文件 )。

在客户机上:

  • 在每台客户端计算机中,您需要在“受信任的根证书颁发机构”存储中选择“计算机帐户”,然后导入根CA证书( ssl-cacert.pem文件)。

随意进行任何更改或建议。