Home > Software design >  Load X509Certificate2 using PEM and not .p12
Load X509Certificate2 using PEM and not .p12

Time:05-05

I have a .p12 cert file that my application needs. Sys admin does not want this file stored in the system. They want to put the value of the file into Azure secrets. As a .pem file.

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

Load the p12

Using the following code i can load the P12 file. The var certHasPrivateKey is true and my code works just fine.

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

var certHasPrivateKey = certificate.HasPrivateKey;

Load the string exported cert.

However if i load this exported text based version the var certHasPrivateKey is false its not loading the private key.

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

var certHasPrivateKey = certificate2 .HasPrivateKey;

How do i load a exported certificate? with the private key.

The issue being

Without having the private key my code is failing as i cant export the subject info.

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

full example

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;
}

CodePudding user response:

The constructor doesn't understand that format. PFX is the only format the constructor understands which returns a certificate that has a bound private key.

To load this kind of data easily, you need to use X509Certificate2.CreateFromPemFile(prem) (.NET 5 ). If you're on something older you'll need to load the cert, independently load the key, and combine them with certWithKey = cert.CopyWithPrivateKey(key).


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

If all you want is the SPKI blob, you could call GetRSAPublicKey instead of GetRSAPrivateKey. (And if you are on .NET 6 you can be more flexible with your supported algorithms by using cert.PublicKey.ExportSubjectPublicKeyInfo())

I suspect it doesn't actually apply, and you're doing something else with the private key later, but it felt worth pointing out nonetheless.

  • Related