如何创建防止 "server mode SSL must use certificate with associated private key" 异常的 X509 证书?

How to create a X509 certificate that prevents "server mode SSL must use certificate with associated private key" exception?

我正在尝试创建一个 X.509 证书文件,该文件将使用 smtp4dev 项目中的以下代码:

var certificate = new X509Certificate(Settings.Default.SSLCertificatePath);
var clientCertificateRequired = false;
var protocols = SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls;
var checkRevocation = false;

var stream = new SslStream(stream);
stream.AuthenticateAsServer(certificate, clientCertificateRequired, protocols, checkRevocation);

Settings.Default.SSLCertificatePath 指向一个 .cer 文件。

无论我尝试什么,都会失败并显示 System.NotSupportedException 消息:

The server mode SSL must use a certificate with the associated private key.

我在提升的 PowerShell 会话中使用 New-SelfSignedCertificate PowerShell CommandLet 创建了一个 X509 证书:

New-SelfSignedCertificate `
    -DnsName "localhost" `
    -CertStoreLocation "cert:\CurrentUser\My" `
    -FriendlyName "smtp4dev" `
    -TextExtension "2.5.29.37={text}1.3.6.1.5.5.7.3.1" `
    -KeyUsage DigitalSignature,KeyEncipherment,DataEncipherment `
    -Provider "Microsoft RSA SChannel Cryptographic Provider"

我添加了这些选项以尽可能接近地镜像已存储在我的计算机上的证书,该证书是由 IIS Express 安装程序生成的。因为那个特定的证书确实有效,虽然我不知道为什么。

两个证书都位于 Local Computer > Personal 证书库中。对于这两个证书,证书管理器都提到 "You have a private key that corresponds to this certificate"。

当我比较这 2 个证书的属性时,smtp4dev 证书与 IIS Express 开发证书在以下 3 方面不同(除了指纹和序列号):

我使用证书管理器将没有私钥的两个证书作为 "Base-64 encoded x.509 (.CER)" 文件导出到我的桌面。 (包括私钥会将导出格式限制为 PKCS #12 (.PFX),smtp4dev 不支持该格式。)

以这种方式导出证书后,当我双击它们时,都没有显示关于拥有私钥的消息。

只有 IIS Express 开发证书适用于此问题开头显示的代码。 smtp4dev 没有。

我尝试的其他事情:

  1. 我经常看到使用 makecert 的教程,但我没有那个程序。

  2. 我尝试使用由 openssl 生成的自签名证书并且只将 Common Name 设置为 localhost 但我得到了相同的异常("The server mode SSL must use a certificate with the associated private key").

  3. 更改代码以使用 X509Certificate2 不是一个选项,因为应用补丁的 smtp4dev 的另一个版本将非常耗时,因为该项目似乎没有被积极开发。

  4. 尝试不同的证书文件格式(例如PFX)其实是可以的,只要我将文件重命名为.cer我就可以欺骗smtp4dev使用证书。这允许我在证书中包含私钥。它适用于导出 IIS Express 开发证书,但不适用于导出 smtp4dev 证书。

我只想到一件事:密钥提供程序兼容性。 SslStream 似乎不支持 CNG KSP(密钥存储提供程序),这是 New-SelfSignedCertificate` cmdlet 的默认密钥提供程序类型。

我建议在 PowerShell 调用中明确指定任何遗留提供程序:

New-SelfSignedCertificate `
    -DnsName "localhost" `
    -CertStoreLocation "cert:\LocalMachine\My" `
    -FriendlyName "smtp4dev" `
    -TextExtension "2.5.29.37={text}1.3.6.1.5.5.7.3.1" `
    -KeyUsage DigitalSignature,KeyEncipherment,DataEncipherment `
    -Provider "Microsoft RSA SChannel Cryptographic Provider"