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

28
我正在使用来自msdn的SSLStream示例,链接在这里。 客户端代码“看起来”正常工作,因为我可以连接到google并至少通过身份验证,但服务器无法连接。
根据msdn页面的评论,我使用了这个页面上的过程生成了自己的私钥,但它就是不起作用。 我收到了一个异常:System.NotSupportedException: The server mode SSL must use a certificate with the associated private key.,所以我相当确定自己所做的一切都是错误的。
所以我的问题很简单:如何获取/生成适用于我从msdn获得的示例程序的密钥?它可以是自签名的,或者任何其他类型的证书,但我对SSL太新了,甚至不知道我需要什么。 我想做的只是按照给出的示例运行,除了为我的本地服务器指定自己的证书之外。如果我只想在两台计算机之间通信,那么在第二台计算机上安装什么东西也会很好(因此不是100%的localhost示例)。
就我个人而言,我认为这是示例文档中的一个缺陷。 它应该说“要运行此程序,您需要执行A、B、C等操作”,但它没有。

你能读取客户端证书吗?我也使用了这个 MSDN 教程。我想读取客户端证书,有什么方法吗? - Jaimesh
3个回答

54
你可以通过自签名证书使示例运行起来。我从使用 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

makecertcert2psc可以在您的Microsoft SDKs\Window\v7.0A\Bin文件夹中找到。您可以从这里(由@Jospeph提供并经过VirusTotal验证)下载pvkImport.exe安装程序。以前可以从微软网站下载此程序,但现在已下架。或者,@Dweeberly向我们指出了一个新的由微软提供的替代品:pvk2pfx

对于接下来的步骤,请确保在pvkimprt的对话框中选择导出私钥:

pvkimprt -pfx TempCert.spc TempCert.pvk

输入图像描述

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

输入图像描述

接下来,将RootCATest.cer导入您的计算机存储区的受信任根证书颁发机构(对于服务器和客户端都是如此)。请注意,证书是颁发给FakeServerName的。这必须与SslTcpClient期望的服务器名称匹配:sslStream.AuthenticateAsClient(serverName),其中serverName是传递给SslTcpClient.exe的第二个参数的值。

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

最后,您需要将服务器将要使用的私钥导入服务器计算机的个人存储区。这一步很重要,因为它涉及服务器模式SSL必须使用具有关联私钥的证书。。这可以通过导入先前生成的.pfx文件来实现。确保将文件类型过滤器更改为“所有文件”,以便您可以看到您生成的.pfx文件:

输入图像描述

MSDN提供的示例代码使用端口443(标准ssl端口)。由于我创建了控制台应用程序,因此我将示例类使用的端口更改为8080:

SslTcpServer:

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

SslTcpClient:

TcpClient client = new TcpClient(machineName, 8080);

这是输出结果: enter image description here 你需要这样启动你的服务器:
SslTcpServer.exe TempCert.cer 

如果是从客户端进行连接,可以按照以下方式连接:

SslTcpClient.exe <ip to your server> FakeServerName

Windows7 有什么变化吗?我在主机服务器模拟器中运行了多年的代码,基于这种技术:http://blogs.technet.com/b/jhoward/archive/2005/02/02/365323.aspx。现在当我运行代码时,我收到与 OP 报告的相同错误,即需要私钥。 - EJA
@Tung,实际上看起来证书创建是现在失败的过程的一部分。"错误:将编码证书保存到存储失败=> 0x5(5)"。无论如何,如果我无法解决我的makecert命令,也许我会尝试您的方法。谢谢! - EJA
@Blub 如果你已经从我的链接下载了 pvkimprt,请记得安装它。通过 Microsoft 下载 link 提供的 pvkImport.exe 不是可执行文件,而是安装程序。 - Tung
@Blub,我的一些观察来自于试错、提问和测试大量的“假设情况”。我希望我能列出一份知识来源清单(因为他们非常值得),但这些年来我与这些来源的关系主要是通过谷歌建立的 :) - Tung
1
看起来微软可能已经用pvk2pfx(https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/pvk2pfx)替换了pvkimprt。 - Dweeberly
显示剩余12条评论

11

使用以下命令生成您的证书:

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

接下来,从客户端以如下方式连接到服务器(假设我们使用了您提到的 MSDN 示例):

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

你在调用ValidateServerCertificate()时会收到验证错误,但这是预期的——因为你正在使用自签名证书。只需返回true即可。

更新:

我不同意Tung建议将自签名证书添加到客户端的受信任根证书颁发机构中。如果您计划分发/支持软件,这可能会在以后引起问题。例如,客户可能重新安装Windows或将其个人资料移到另一台计算机上,或者出现其他情况,当您完全忘记这个小“技巧”时,了解为什么您的软件突然停止工作将会很痛苦(再次强调,我指的是长期而言,一两年后)。

相反,我更倾向于将你的证书(通过比较主题和Thumbprint)“硬编码”到客户端的逻辑中,像这样:

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

1
然后您需要获取真正的SSL证书 :) 验证检查WINDOWS信任您证书的根 - 而根是LOCALHOST。当然它不被信任。我发送给您的链接描述了如何检查证书的其他属性以进行手动验证 - 这意味着如果您将应用程序与证书一起发送给其他用户,您可以使用这些检查来确保他们没有替换您的证书为其他证书。 - avs099
1
@MattWolc24 正确,流仍然是加密的 - 你只是不知道是否可以“信任”密钥以及是否有其他人可以读取它。 - avs099
1
@MattWolc24 是的,如果您盲目地信任任何证书,恶意方可以读取您的消息内容。但是,如果您与第三方服务器合作,则没有选择 - 要么信任它呈现的证书(如果未经公共CA签名),要么停止与其通信。 - avs099
由于在您的示例中我们正在验证拇指印,那么恶意方必须要制作证书的“副本”,对吗?这是可能的吗?据我所知,如果他们自己制作证书,那么它将具有不同的拇指印,因此他们必须获取访问我的服务器并复制我的证书。 - MattWolc24
1
@MattWolc24 如果你控制服务器,那么你就不必担心这个问题了。是的,除非你泄露证书,否则没有人会知道并且无法访问你的加密数据。 - avs099
显示剩余10条评论

6
作为Microsoft下载pvkimprt的链接已经失效,而我是OpenSSL的粉丝,所以在这里提供两个使用OpenSSL的解决方案。 变体#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

让我们创建证书申请,通用名称必须设置为机器名称:

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证书分发给客户端。
首先下载this配置文件。
我们将使用相应的私钥生成根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

非常重要的是将通用名称设置为服务器的机器名称。
验证此证书请求的信息:
openssl req -text -noout -verify -in ssl-servercert.csr

信息展示必须具有以下格式,请检查主题部分中的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-certificate.pfx文件)。
在客户端上: - 在每个客户端计算机上,选择计算机帐户,在受信任的根证书颁发机构存储中导入根CA证书(ssl-cacert.pem文件)。
如有任何更改或建议,请随意提出。

我们需要使用哪个X509Certificate2构造函数来处理这个.pfx文件? - Dadkhah
我们需要使用哪个X509Certificate2构造函数来处理这个.pfx文件? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接