X509Certificate构造函数异常


73
//cert is an EF Entity and 
//    cert.CertificatePKCS12 is a byte[] with the certificate.

var certificate = new X509Certificate(cert.CertificatePKCS12, "SomePassword");

当从数据库中加载证书时,在暂存服务器(Windows 2008 R2 / IIS7.5)上,会出现以下异常:

System.Security.Cryptography.CryptographicException: An internal error occurred.

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
   at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)

注意:此问题不会在本地发生(Windows 7 / Casini)。

非常感谢任何见解。



1
我想,这个问题的根源是在byte[] 数据cert.CertificatePKCS12。没有数据,只能猜测“发生内部错误”异常的原因。因此,我的建议是创建一个可在您的环境中使用的测试证书,以重现问题,将其保存在文件中,并提供用于解码证书的链接和密码(例如“ SomePassword”)。在检查了数据之后将有更多的机会找到共鸣并提出解决问题的建议。
奥莱格(Oleg)2012年

感谢@Oleg的答复-如果字节数组不正确,在Win7和Win2k8上都不会出错吗?将字节数组写入文件后,它将正确导入。
lukiffer 2012年

@lukiffer:我的意思不是说错误,而是结合了证书,密钥等的某些属性。因此,必须分析问题。为了能够重现结果或对其进行分析,需要使用PFX文件作为字节数组cert.CertificatePKCS12
Oleg 2012年

@oleg-哪些属性会导致它在一个操作系统而不是另一个操作系统上失败?出于明显的安全原因,我们无法自行发布证书。
lukiffer 2012年

Answers:


127

事实证明,IIS应用程序池配置中有一个设置(应用程序池>高级设置)可以为应用程序池标识用户加载用户配置文件。设置为false时,将无法访问密钥容器。

因此,只需将Load User Profileoption设置为True

应用程序池->高级设置屏幕


请注意,这是针对IIS7的。在IIS6中,我认为没有选项可以加载用户配置文件。
兰迪(Randy)

2
我正在尝试在Azure上执行此操作,但我不知道可以更改“加载用户配置文件”选项。任何建议...我对证书世界还是一个新手...
Dan B

1
@DanB为天青添加应用程序设置:WEBSITE_LOAD_USER_PROFILE = 1
EMP

61

从Visual Studio / Cassini运行时,即使从字节中加载它,也很有可能正在访问用户证书存储。您可以尝试一下,看看是否能解决您的问题:

var certificate = new X509Certificate(
    cert.CertificatePKCS12, "SomePassword", X509KeyStorageFlags.MachineKeySet);

这将导致IIS(以ASP.NET用户身份运行,该用户可能无权访问用户存储)使用计算机存储。

本页更详细地说明了构造函数,而本页则说明了X509KeyStorageFlags枚举。

编辑: 基于对第二链路cyphr,它看起来像它可能是一个好主意(如果前面的解决方案不工作),对一些结合起来FlagsAttribute,像这样枚举值:

var certificate = new X509Certificate(
    cert.CertificatePKCS12, "SomePassword",
    X509KeyStorageFlags.MachineKeySet
    | X509KeyStorageFlags.PersistKeySet
    | X509KeyStorageFlags.Exportable);

此外,如果您具有访问权限,则可能需要尝试将应用程序池设置更改为使用LocalService(然后重新启动AppPool)。如果这是问题所在,这可能会将您的权限提升到适当的级别。

最后,您可以使用File.WriteAllBytesCertificatePKCS12内容写到pfx文件中,并查看是否可以使用MMC下的证书控制台手动导入它(可以在成功导入后删除;这只是为了测试)。可能是您的数据不完整或密码不正确。


感谢您的答复,虽然刚加入后它仍然抛出同样的异常X509KeyStorageFlags.MachineKeySet标志,以及添加所有三个的时候MachineKeySetPersistKeySetExportable标志。
lukiffer 2012年

1
您可以将AppPool的身份更改为LocalService吗?
克里斯·贝纳德

另外,还可以File.WriteAllBytes用于将CertificatePKCS12内容写到pfx文件中,并查看是否可以在MMC下使用证书控制台手动导入它(可以在成功导入后删除;这只是为了测试)。可能是您的数据不完整或密码不正确。
克里斯·贝纳德

1
好。我更新了答案,以包括那些可以解决的问题。我正在尝试赚+50。:)
克里斯·贝纳德

1
请注意,如果您打算SignTool.exe从ASP.NET项目进行调用,则仍需要为启用“ LoadUserProfile” Application Pool。否则SignTool.exe将因An internal error occurred错误而失败...
c00000fd

32

使用此代码:

certificate = new X509Certificate2(System.IO.File.ReadAllBytes(p12File)
                                   , p12FilePassword
                                   , X509KeyStorageFlags.MachineKeySet |
                                     X509KeyStorageFlags.PersistKeySet | 
                                     X509KeyStorageFlags.Exportable);

1
只需将3或语句添加到最后,我的工作就可以开始。好的代码仍然有意义。
Jobokai

1
在尝试将证书作为IIS上的嵌入式资源加载时为我工作。
罗宾·范德·纳纳普

这是我使用spire.pdf时遇到的问题
HaBo

8

我在Windows 2012 Server R2上遇到问题,该应用程序无法在磁盘上加载PFX的证书。一切都可以以管理员身份运行我的应用程序,并且运行状况很好,但异常显示“访问被拒绝”,因此必须是权限问题。我尝试了上述一些建议,但仍然有问题。我发现将以下标志指定为cert构造函数的第三个参数对我来说很有效:

 X509KeyStorageFlags.UserKeySet | 
 X509KeyStorageFlags.PersistKeySet | 
 X509KeyStorageFlags.Exportable

2

为了能够真正解决您的问题,而不仅仅是猜测,这可能是什么,一个人必须能够重现您的问题。如果您不能提供存在相同问题的测试PFX文件,则必须自己检查问题。第一个重要的问题是:PKCS12的私钥部分还是证书本身的公共部分中的异常“起源是内部错误发生”?

因此,我建议您尝试使用相同的证书(不带私钥(如.CER文件)导出)重复相同的实验:

var certificate = new X509Certificate(cert.CertificateCER);

要么

var certificate = new X509Certificate.CreateFromCertFile("My.cer");

这可能有助于验证问题的根源是私钥还是证书的某些属性。

如果您对CER文件有疑问,可以安全地将链接发布到该文件,因为它仅具有公共信息。或者,您至少可以执行

CertUtil.exe -dump -v "My.cer"

要么

CertUtil.exe -dump -v -privatekey -p SomePassword "My.pfx"

(您也可以使用其他选项)并发布输出的某些部分(例如,不具有PRIVATEKEYBLOB本身的私钥属性)。



1

您需要将.cer证书导入本地计算机密钥库。无需导入您的.p12证书-而是使用Apple发行给您帐户的第二个证书。我认为它必须是一对有效的证书(一个在文件系统中,第二个在密钥库中)。当然,您必须在dll中设置所有3个标记。


0

在运行IIS 10的应用程序上,我通过使用以下代码对应用程序池使用LocalSystem标识来解决了拒绝访问错误:

new X509Certificate2(certificateBinaryData, "password"
                               , X509KeyStorageFlags.MachineKeySet |
                                 X509KeyStorageFlags.PersistKeySet);

启用“加载用户配置文件”对我不起作用,尽管有很多建议可以这样做,但它们并未表明将“加载用户配置文件”设置为True仅适用于用户帐户,而不适用于:

  1. 应用程序池标识
  2. 网络服务

0

以下代码将为您提供帮助,您可以使用充气城堡库生成算法:

private static ECDsa GetEllipticCurveAlgorithm(string privateKey)
{
    var keyParams = (ECPrivateKeyParameters)PrivateKeyFactory
        .CreateKey(Convert.FromBase64String(privateKey));

    var normalizedECPoint = keyParams.Parameters.G.Multiply(keyParams.D).Normalize();

    return ECDsa.Create(new ECParameters
    {
        Curve = ECCurve.CreateFromValue(keyParams.PublicKeyParamSet.Id),
        D = keyParams.D.ToByteArrayUnsigned(),
        Q =
    {
        X = normalizedECPoint.XCoord.GetEncoded(),
        Y = normalizedECPoint.YCoord.GetEncoded()
    }
    });
}

并通过以下方式生成令牌:

var signatureAlgorithm = GetEllipticCurveAlgorithm(privateKey);

        ECDsaSecurityKey eCDsaSecurityKey = new ECDsaSecurityKey(signatureAlgorithm)
        {
            KeyId = settings.Apple.KeyId
        };

        var handler = new JwtSecurityTokenHandler();   
        var token = handler.CreateJwtSecurityToken(
            issuer: iss,
            audience: AUD,
            subject: new ClaimsIdentity(new List<Claim> { new Claim("sub", sub) }),
            expires: DateTime.UtcNow.AddMinutes(5), 
            issuedAt: DateTime.UtcNow,
            notBefore: DateTime.UtcNow,
            signingCredentials: new SigningCredentials(eCDsaSecurityKey, SecurityAlgorithms.EcdsaSha256));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.