【问题标题】:Loading X509Certificate2 ends with An internal error occurred on Windows server 2012加载 X509Certificate2 以 Windows server 2012 上发生内部错误结束
【发布时间】:2021-12-07 11:21:48
【问题描述】:

我正在尝试从路径加载证书并在 Windows 服务器上出现内部服务器错误。虽然我在 Windows 10 上执行此操作,但一切正常。

不工作的控制台应用程序代码

var path = args[0];
var password = args[1];
var certificate2 = new X509Certificate2(path, password);

但出现错误

Unhandled exception. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: An internal error occurred.
   at Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[] rawData, SafePasswordHandle password, PfxCertStoreFlags pfxCertStoreFlags)
   at Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[] rawData, String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password)
   at CertCoreTest.Program.Main(String[] args) in C:\Users\Admin\Documents\Visual Studio 2019\Projects\CertTest\CertCoreTest\Program.cs:line 12

破解工作代码(不知道为什么会起作用)

var path = args[0];
var password = args[1];

Chilkat.Cert cert = new Chilkat.Cert();
var success = cert.LoadPfxData(File.ReadAllBytes(path), password);
if (success == false)
{
    throw new Exception(cert.LastErrorText);
}

var bytes = cert.ExportToPfxData(password, true);
var ceeert = new X509Certificate2(bytes, password);

如何在不使用 chilkat 库的情况下使其在 windows 服务器上运行?

【问题讨论】:

  • 您是否在两个平台上运行完全相同的可执行文件?和相同的证书文件?您是否都以管理员身份运行?
  • 是的,我运行的完全一样
  • 不知道你在PFX中使用的算法是不是9年前就没有了?
  • 一些非常好的建议here。这可能与潜在的权限问题有关。证书可能会存储一些信息以访问用户在服务器(即机器)上没有被授予访问权限的存储。或者按照帖子中的建议开一家商店可能会有所帮助。
  • @user2279379 您能否提供有关该文件的更多详细信息?加密算法、PKCS #12 版本、文件保护类型、...

标签: c# .net windows-server-2012 x509certificate2 chilkat


【解决方案1】:

如果您的代码在 IIS 下的 Web 应用程序中运行:

  1. 转到 IIS 管理器
  2. 转到应用程序池实例
  3. 点击高级设置
  4. 在进程模型下,将加载用户配置文件设置为 true

否则,请尝试指定 UserKeySet(PFX 内部可能包含“使用机器存储”标记):

var path = args[0]; var password = args[1]; var certificate2 = new X509Certificate2(path, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.EphemeralKeySet);

否则,在本地机器上安装证书并尝试通过指纹从存储加载:

如果上述方法失败,则可能无法使用 Windows 2012 内置工具将 .p12 文件导入 Windows 2012。要检查: “对于每个 PKCS #12 文件,您可以尝试以下操作:发出命令 certutil -asn | findstr /i "pb aes des sha"(将 "" 替换为 PKCS #12 文件的名称)。

如果输出开始如下:

| | | | | ; 1.2.840.113549.1.12.1.3 szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES

那么应该可以将 PKCS #12 文件导入 Windows 2016。

如果输出开始如下:

| | | | | ; 1.2.840.113549.1.5.13 szOID_PKCS_5_PBES2 | | | | | | ; 1.2.840.113549.1.5.12 szOID_PKCS_5_PBKDF2 | | | | | ; 2.16.840.1.101.3.4.1.42 aes256

或类似的,那么 PKCS #12 文件可能无法使用内置的 Windows 2016 工具导入到 Windows 2016 中。您必须使用 TripleDES 和 SHA1 重新创建 PKCS #12 文件。” - 参见线程:https://docs.microsoft.com/en-us/answers/questions/518605/importing-a-pkcs12-to-windows-server-2016.html

【讨论】:

  • 我的代码没有在 IIS 下运行。它的控制台应用程序。
  • @user2279379 你试过上面的第二种方法了吗?
  • 是的,我做了,没用
  • 您是否尝试直接传递 .pfx 字节(不是通过 Chilkat.Cert): var certificate2 = new X509Certificate2(System.IO.File.ReadAllBytes(path), password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags .EphemeralKeySet);
  • 它的 .p12 文件。我确实使用您的代码通过了它但没有工作。
【解决方案2】:

您是否尝试将字节数据传递到X509Certificate2 而不是传递路径?从official document查看下面的src。

我在从 HTTP 调用加载时遇到了类似的问题。我必须通过cert.GetRawCertData()(与您的情况不同,但似乎原因相似)

using System;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.IO;
using System.Security.Cryptography.X509Certificates;

class CertInfo
{
    //Reads a file.
    internal static byte[] ReadFile (string fileName)
    {
        FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        int size = (int)f.Length;
        byte[] data = new byte[size];
        size = f.Read(data, 0, size);
        f.Close();
        return data;
    }
    //Main method begins here.
    static void Main(string[] args)
    {
        //Test for correct number of arguments.
        if (args.Length < 1)
        {
            Console.WriteLine("Usage: CertInfo <filename>");
            return;
        }
        try
        {
            X509Certificate2 x509 = new X509Certificate2();
            //Create X509Certificate2 object from .cer file.
            byte[] rawData = ReadFile(args[0]);
            x509.Import(rawData);

            //Print to console information contained in the certificate.
            Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine, x509.Subject);
            Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer);
            Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine, x509.Version);
            Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, x509.NotBefore);
            Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine, x509.NotAfter);
            Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine, x509.Thumbprint);
            Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine, x509.SerialNumber);
            Console.WriteLine("{0}Friendly Name: {1}{0}", Environment.NewLine, x509.PublicKey.Oid.FriendlyName);
            Console.WriteLine("{0}Public Key Format: {1}{0}", Environment.NewLine, x509.PublicKey.EncodedKeyValue.Format(true));
            Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine, x509.RawData.Length);
            Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine, x509.ToString(true));
            Console.WriteLine("{0}Certificate to XML String: {1}{0}", Environment.NewLine, x509.PublicKey.Key.ToXmlString(false));

            //Add the certificate to a X509Store.
            X509Store store = new X509Store();
            store.Open(OpenFlags.MaxAllowed);
            store.Add(x509);
            store.Close();
        }
        catch (DirectoryNotFoundException)
        {
               Console.WriteLine("Error: The directory specified could not be found.");
        }
        catch (IOException)
        {
            Console.WriteLine("Error: A file in the directory could not be accessed.");
        }
        catch (NullReferenceException)
        {
            Console.WriteLine("File must be a .cer file. Program does not have access to that type of file.");
        }
    }
}

【讨论】:

  • 您的代码缺少密码参数。尝试添加密码和 0 作为标志。没有帮助。
【解决方案3】:

为私钥使用本地计算机存储:

X509Certificate2 cert = new X509Certificate2("yourhost.pfx", "password", X509KeyStorageFlags.MachineKeySet);

MachineKeySet 被描述为私钥存储在本地计算机存储中,而不是当前用户存储中。没有标志的默认是放置在用户存储中。

即使您从磁盘读取证书并将其存储在对象中,私钥仍存储在Microsoft Cryptographic API 加密服务提供程序密钥数据库中。 在托管服务器上,ASP.NET 进程无权访问用户存储。

另一种方法:(如果您将应用程序控制台更改为 Web)
修改 IIS 配置或应用程序池标识——它们确实有效。但是,这假设可以访问这些配置项,但情况可能并非如此(例如,在共享主机环境中)。

You can read more about MSDN.System.Security.Cryptography.X509Certificates

【讨论】:

  • 已经试过了。没用。
  • 在托管服务器上,ASP.NET 进程无权访问用户存储,但 Windows 10 上的本地工作正常。如果你在服务器上尝试IIS,你可以访问。
  • 但是我正在使用控制台应用程序甚至 IIS 加载证书。
猜你喜欢
  • 2010-11-23
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 2016-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
相关资源
最近更新 更多