使用 PEM 而不是 .p12 加载 X509Certificate2

Load X509Certificate2 using PEM and not .p12

我有一个我的应用程序需要的 .p12 证书文件。系统管理员不希望将此文件存储在系统中。他们想将文件的值放入 Azure 机密中。作为 .pem 文件。

-----BEGIN PRIVATE KEY-----
.
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
................
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
.................
-----END CERTIFICATE-----

加载 p12

使用下面的代码我可以加载 P12 文件。 var certHasPrivateKey 是真的,我的代码工作得很好。

// Load the cert as p12
var certificate = new X509Certificate2(pathToCert, certPassword,
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet  | X509KeyStorageFlags.Exportable);

var certHasPrivateKey = certificate.HasPrivateKey;

加载导出的字符串证书。

但是,如果我加载这个导出的基于文本的版本,则 var certHasPrivateKey 为假,它不会加载私钥。

// Load the cert as string
var certificate2 = new X509Certificate2(p12Export, certPassword,
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

var certHasPrivateKey = certificate2 .HasPrivateKey;

如何加载导出的证书?使用私钥。

问题是

如果没有私钥,我的代码会失败,因为我无法导出主题信息。

 var key = certificate.GetRSAPrivateKey();
 var pubKeyBytes = key.ExportSubjectPublicKeyInfo();

完整示例

using System.Security.Cryptography.X509Certificates;
Console.WriteLine("Hello, World!");

var pathToCert = "C:\Development\KMDDIMA\CredsForAuth\RealP12File.p12";
var certPassword = "Magda2015";
var prem = "C:\Development\KMDDIMA\CredsForAuth\cert.pem";

// Load the cert as p12  (Works)
var certificate = new X509Certificate2(pathToCert, certPassword,
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
var p1 = certificate.HasPrivateKey;


try
{
// Load the cert prem as just the file  (Error: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Cannot find the requested object.)
    var certPremFile = new X509Certificate2(prem, certPassword,
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
    var certPremFilePrivateIsSet = certPremFile.HasPrivateKey;
    Console.WriteLine(certPremFilePrivateIsSet);
}
catch (Exception e)
{
    Console.WriteLine(e);
    //throw;
}

try
{
// Load the cert as prem as a byte array (Error: Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Cannot find the requested object.)
    var certPremBytes = File.ReadAllBytes(prem);
    var certPremLoadedWithBytes = new X509Certificate2(certPremBytes, certPassword,
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
    var p2HasPrivateKey = certPremLoadedWithBytes.HasPrivateKey;

    Console.WriteLine(p2HasPrivateKey);
}
catch (Exception e)
{
    Console.WriteLine(e);
    //throw;
}

构造函数不理解该格式。 PFX 是构造函数理解的唯一格式,returns 具有绑定私钥的证书。

要轻松加载此类数据,您需要使用 X509Certificate2.CreateFromPemFile(prem) (.NET 5+)。如果您使用的是旧版本,则需要加载证书,独立加载密钥,并将它们与 certWithKey = cert.CopyWithPrivateKey(key).

组合
var key = certificate.GetRSAPrivateKey();
var pubKeyBytes = key.ExportSubjectPublicKeyInfo();

如果您只需要 SPKI blob,则可以调用 GetRSAPublicKey 而不是 GetRSAPrivateKey。 (如果您使用的是 .NET 6+,则可以使用 cert.PublicKey.ExportSubjectPublicKeyInfo() 更灵活地使用支持的算法)

我怀疑它实际上并不适用,您稍后会用私钥做其他事情,但仍然值得指出。