在 C# 中以编程方式将 .crt + .key 文件转换为 X509Certificate2

Convert .crt + .key files to X509Certificate2 programmatically in C#

我在 Linux 机器上有一个 .crt 证书和一个 .key 私钥文件。私钥采用加密的 PKCS#8 格式(BEGIN ENCRYPTED PRIVATE KEY...)。我想将它们导入 X509Certificate2 对象以供进一步使用。由于我们在 Linux,我们正在使用 .NET Core 2.2(我们还不能迁移到 3.0)。

我探索了一些可能的解决方案,详情如下:

  1. 使用 openssl 将文件转换为 .pfx 并使用 X509Certificate2 导入
    • 我不想使用此选项,因为我不想从 C# 中执行 shell 代码。我希望在 C# 中完全以编程方式实现解决方案。
  2. 使用 C# BouncyCastle 库执行以下任一操作:
    • 将证书和密钥都转换为 .pfx(如上所述),或者
    • 分别导入证书和私钥,并使用X509Certificate2.CopyWithPrivateKey()组合。
    • 但是,我找不到 API 的 BouncyCastle C# 版本,所以我不确定我可以使用什么方法来做到这一点。
  3. 我在此处遗漏的其他一些 C# 编程方法

本质上,最终目标是从 .crt 和 .key 文件中获取 X509Certificate2 对象。任何 help/insight 关于使用什么方法,甚至指向有用的 BouncyCastle 文档的指针,都将不胜感激。谢谢!

这在 .NET Core 3.0 中是可能的,尽管不是那么友好:

private static byte[] UnPem(string pem)
{
    // This is a shortcut that assumes valid PEM
    // -----BEGIN words-----\nbase64\n-----END words-----
    const string Dashes = "-----";
    int index0 = pem.IndexOf(Dashes);
    int index1 = pem.IndexOf('\n', index0 + Dashes.Length);
    int index2 = pem.IndexOf(Dashes, index1 + 1);

    return Convert.FromBase64String(pem.Substring(index1, index2 - index1));
}

...

string keyPem = File.ReadAllText("private.key");
byte[] keyDer = UnPem(keyPem);
X509Certificate2 certWithKey;

using (X509Certificate2 certOnly = new X509Certificate2("certificate.cer"))
using (RSA rsa = RSA.Create())
{
    // For "BEGIN PRIVATE KEY"
    rsa.ImportPkcs8PrivateKey(keyDer, out _);
    certWithKey = certOnly.CopyWithPrivateKey(rsa);
}

using (certWithKey)
{
    Console.WriteLine(certWithKey.HasPrivateKey);
}

RSA 私钥可以采用三种不同的格式,您需要为每种格式调用正确的导入:

  • "BEGIN PRIVATE KEY": ImportPkcs8PrivateKey
  • "BEGIN ENCRYPTED PRIVATE KEY":ImportEncryptedPkcs8PrivateKey
  • "BEGIN RSA PRIVATE KEY":导入RSAPrivateKey

在 .NET 5 中,这变得尽可能简单:

var certificate =
  X509Certificate2.CreateFromPemFile(
    crtFile,
    Path.ChangeExtension(crtFile, "key"));