【问题标题】:SSLStream example - how do I get certificates that work?SSLStream 示例 - 我如何获得有效的证书?
【发布时间】:2012-04-16 11:50:19
【问题描述】:

我正在使用来自 msdn here 的 SSLStream 示例。客户端代码“似乎”工作正常,因为我可以连接到谷歌并且它至少通过了身份验证,但服务器没有。

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

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

我个人认为这是示例文档中的一个缺陷。它应该说“要运行它,你需要执行 A、B、C 等”,但它没有。

【问题讨论】:

  • 你能读取客户端证书吗???我也使用这个 msdn 教程。我想阅读客户证书?这怎么可能?

标签: c# ssl certificate


【解决方案1】:

使用此命令生成您的证书:

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

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

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

您将在 ValidateServerCertificate() 调用中收到验证错误 - 但这是意料之中的 - 您使用的是自签名证书。只需在此处返回 true。

更新:

我不同意 Tung 将自签名证书添加到客户的受信任根证书颁发机构的建议。如果您计划分发/支持您的软件,我认为它可能会在以后引起问题。例如,客户可能会重新安装 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;

【讨论】:

  • 我很想把这个给你,因为这是第一个通过我的机器上的身份验证获得服务器而不抱怨证书的答案/解决方案,但是客户端没有t 工作,这不是 100% 满足我的需求。所以你非常接近正确的程序。
  • 那么您需要获得真正的 SSL 证书 :) 验证检查 WINDOWS 是否信任您的证书的根 - 并且根是 LOCALHOST。当然不可信。我发送给您的链接描述了如何检查证书的其他属性以对其进行手动验证 - 这意味着如果您将您的应用程序与您的证书一起发送给其他用户,您可以使用这些检查来确保他们没有将您的证书替换为另一个。
  • @MattWolc24 正确,流仍然是加密的 - 你只是不知道你是否可以“信任”密钥以及其他人是否可以读取它。
  • @MattWolc24 是的,如果您盲目信任所提供的任何证书,恶意方可以读取您的消息内容。如果您使用 3rd 方服务器,但您实际上别无选择 - 要么信任它提供的证书(如果它没有由公共 CA 签名),要么停止与之通信。
  • @MattWolc24 如果您控制服务器,则不必担心这一点。是的,除非您泄露证书,否则没有人会知道并且无法访问您的加密数据。
【解决方案2】:

即使使用自签名证书,您也可以让该示例正常工作。我已经从您正在使用的 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 文件夹中找到。 pvkImport.exe 安装程序可以从here (Provided by @Jospeph and VirusTotal verified) 下载。这曾经可以从 Microsoft 站点下载,但后来他们将其删除。或者,@Dweeberly 向我们指出了 Microsoft 提供的新替代品pvk2pfx

对于下一步,请确保在 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 文件来实现的。确保将文件类型过滤器更改为“所有文件”,以便您可以看到生成的 .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 <ip to your server> FakeServerName

【讨论】:

  • 今晚我要离开,但我会稍后再试。我喜欢它的详细程度以及为什么。
  • 工作。非常感谢。 'net 上没有其他解决方案可以使用未更改的代码,但您的解决方案可以。谢谢。
  • @Morvader,我想唯一的区别是获取证书管理管理单元的方法。路线可以找到here
  • Windows7 有什么变化吗?基于这种技术,我在主机服务器模拟器中运行了多年的代码:blogs.technet.com/b/jhoward/archive/2005/02/02/365323.aspx。现在,当我运行代码时,我得到了与 OP 报告的相同的错误,即需要私钥。
  • 看来MS可能已经用pvk2pfx替换了pvkimprt (docs.microsoft.com/en-us/windows-hardware/drivers/devtest/…)
【解决方案3】:

由于要下载 pvkimprt 的 Microsoft link 已损坏,而我是 OpenSSL 的粉丝,我在这里留下了两个 OpenSSL 解决方案。

变体 #1 - 自签名证书

首先您需要下载OpenSSL 和此配置file。 @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. 选择个人商店并点击下一步。

这个步骤必须工作。

变体 #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

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

验证此证书请求的信息:

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 &gt; 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 文件)。

随时提出任何更改或建议。

【讨论】:

    猜你喜欢
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多