X509Certificate2 构造函数中的“指定的网络密码不正确”异常

7
我有一个控制台应用程序,可以按以下方式从字节数组中加载X509证书:

var cert = new X509Certificate2(certificateContent,      // byte[]
                                password,                // string
                                X509KeyStorageFlags.PersistKeySet);

certificateContent是一个byte[],表示pfx文件的内容。我已经测试过几个证书,这段代码可以正常工作。但现在我正在测试另一个证书,使用这行代码时会抛出一个CryptographicException,错误信息是“指定的网络密码不正确”,尽管提供的密码是正确的。

奇怪的是,我可以在LinqPad中使用相同的代码从相同的pfx文件和密码创建证书,而且它可以正常工作。

我已经在调试器中检查了控制台应用程序的调用站点,并验证了传入的正确值。

是什么原因导致这个构造函数在控制台应用程序中抛出此异常,而在使用相同数据的LinqPad中没有抛出异常,而且对于其他证书在两个地方都能很好地工作呢?

更多细节

证书以Base64格式存储在数据库中。控制台应用程序从数据库读取证书,将其从Base64转换为byte[],然后尝试像上面那样创建X509Certificate2对象。

我一直在测试三个证书:

  1. 由我的雇主CA提供的个人客户端身份验证证书。
  2. 由同事使用其自己的自签名CA创建的测试证书。
  3. 我自己使用自签名CA创建的测试证书。

证书1和2在控制台应用程序和LinqPad中都能正常工作。而证书3可以在LinqPad中加载,但如果我尝试在控制台应用程序中使用它,则会生成上面的错误。

证书2和3之间有两个显著的差异:

  1. 证书2将在2016年过期,证书3将在2039年过期。
  2. 与证书2关联的私钥长度为2048位,而证书3是1024位。

这些差异是否会导致“指定的网络密码不正确”错误?为什么三个证书在LinqPad中都能很好地工作,但只有一个在控制台应用程序中抛出了异常呢?


证书/证书的私钥是否已安装在CertMgr.msc中?您使用的是哪个操作系统?您的应用程序是否针对与LinqPad运行的相同的.NET Framework版本? - EricLaw
Linqpad和您的应用程序是否使用相同的凭据运行?包括以提升的权限运行吗?我认为您需要提升权限才能在代码中访问证书存储。 - Mike Cheel
@MikeCheel - 是的,两者都在我的帐户下运行,该帐户在计算机上具有管理员权限。我尝试过以提升和非提升的方式运行,但结果相同。当以非提升的方式运行时,我测试过的其他证书都可以正常工作,并且LinqPad没有以提升的方式运行,但对于这个问题证书可以正常工作。 - Andrew Cooper
2
尝试使用MachineKeySet(或MachineKeySet | PersistKeySet)怎么样? - Mike Cheel
1
@MikeCheel 使用 X509KeyStorageFlags.MachineKeySet 解决了我的问题,谢谢! - Cocowalla
显示剩余11条评论
5个回答

4
在我的情况下,我有一个自签名证书,通过MMC (Microsoft Management Console) 导出,并设置了密码。在我的机器(win10)上加载这个证书没有问题,但在一台服务器机器上却抛出异常并显示 "指定的网络密码不正确"。
在我的情况下解决问题的方法是什么?当我导出证书时,我使用了AES256-SHA256设置密码,但是该证书加密在服务器机器上不受支持(参考此dotnet runtime issue)。当我将其更改为TripleDES-SHA1时,本地和服务器上都可以正常工作。
来自dotnet运行时问题的引用:

WindowsCryptographicException:内部错误发生的原因可能是PFXImportCertStore失败,返回null并调用带NTE_FAIL的SetLastError。

我猜测可能会导致这种情况的原因:

  • PFX是使用不同的加密密码和完整性密码创建的,并且完整性密码是提供给构造函数的。但如果同一个PFX文件在任何Windows机器上都能正常工作,则不会出现这种情况。
  • PFX是使用PKCS12_PROTECT_TO_DOMAIN_SIDS创建的,与另一端通信时存在某种问题。我认为我们不支持这种类型的PFX。该PFX是使用https://www.rfc-editor.org/rfc/rfc7292#appendix-B中的指导生成的,即使用PBES2+PBKDF2加密私钥而非pbeWithSHAAnd3-KeyTripleDES-CBC。在这种情况下,PFX将在Windows 10上打开,但不会在先前版本上打开。(至少我记得这是我遇到此案例时的行为)。如果我没有记错,它也不会在macOS上打开。
  • PKCS#12 v1.1还讨论了使用非对称加密而不是基于密码的方案对PFX进行加密和/或签名的方法。但我不知道甚至Win10是否支持这一点,因为我在PFXExportCertStoreEx中没有看到任何控件。所以我能想到唯一有意义的事情就是你有一个“新”的PFX,你的测试环境是Windows 10,但是你的生产环境是Win2012R2。

2
希望这能对某些人有所帮助:
用户“S C”指出了在Windows XP和Windows Server 2003上使用证书密码的以下要求。 (原文链接)
0 < password.Length < 32

我看到了一些关于是否允许32个字符的矛盾报告。我可以确认,我使用了一个32个字符的密码(MD5哈希),将其截断为30个字符后问题得到了解决。


谢谢,我一直在为一个40个字符的密码而苦恼...为什么Windows甚至允许你导出它... - Peroxy

0
Public Function sign(keystore As String, level As Integer, src As String, name As String,dest As String, sig As String, pass As String)

        'Dim store As System.Security.Cryptography.X509Certificates.X509Store = New System.Security.Cryptography.X509Certificates.X509Store
        'store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly)
        'Dim sel As System.Security.Cryptography.X509Certificates.X509Certificate2Collection

        ' If sig <> "" And pass <> "" Then
        Try


            Dim y As Int16 = 200
            ' For i As Integer = 0 To sel.Count - 1
            Dim pdfReader As PdfReader = New PdfReader(src)
            Dim signedPdf = New FileStream(dest, FileMode.Create)
            Try
                Dim cert As X509Certificate2 = New X509Certificate2(sig, pass)

                Dim cp As Org.BouncyCastle.X509.X509CertificateParser = New Org.BouncyCastle.X509.X509CertificateParser()
                Dim chain As Org.BouncyCastle.X509.X509Certificate() = New Org.BouncyCastle.X509.X509Certificate() {cp.ReadCertificate(cert.RawData)}




                Dim stamper As PdfStamper
                stamper = PdfStamper.CreateSignature(pdfReader, signedPdf, "0"c, Nothing, True)
                Dim signatureAppearance As PdfSignatureAppearance = stamper.SignatureAppearance
                'signatureAppearance.SignatureGraphic = Image.GetInstance(pathToSignatureImage)
                signatureAppearance.SetVisibleSignature(name)

                signatureAppearance.CertificationLevel = level
                Dim externalSignature As IExternalSignature = New X509Certificate2Signature(cert, "SHA-1")
                ' Dim digest As IExternalSignature = New BouncyCastleDigest
                ' signatureAppearance.s 
                'signatureAppearance.SetVisibleSignature(New Rectangle(50,50,50,
                signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION
                MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, Nothing, Nothing, Nothing, 0, CryptoStandard.CADES)
                ' MakeSignature. 



            Catch ex As Exception

                MsgBox("Signature File Password is not correct for the user Id :" & error_userid)
                'Exit Function
            End Try
        Catch ex As Exception
            'MsgBox(ex.Message)
        End Try
        ' End If
        Return 0
    End Function

0
根据uGeeen的回答,在Windows Server 2003或Windows XP上创建的证书应该有密码,否则会抛出此异常。

0

以下代码对我有效。

var fileName = Path.Combine(rootPath, "cert.pfx");

if(!File.Exists(fileName)) {
    throw new FileNotFoundException("Signing Certificate is missing!");
}

var cert = new X509Certificate2(fileName,"123456789");

其中 "123456789" 是我的密码


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