I've got a .PEM file that I want to convert to a PKCS12 file (PFX), and I know I can easily accomplish this using the following openssl
command:
Create a PKCS#12 file: openssl pkcs12 -export -in file.pem -out file.p12 -name "My Certificate"
Which is great, but I'd like to do this programmatically using OpenSSL calls. Unfortunately, documentation for OpenSSL is less than ideal.
I've looked into doing this using other libraries:
Using .NET: I can create a X509Certificate2 object from a PEM file, but this only grabs the first certificate and ignores any intermediate CA's in the PEM file.
Using Mentalis.org Security Library: I can create a Certificate object from a PEM file, but I see the following in the documentation:
Remarks This implementation only reads certificates from PEM files. It does not read the private key from the certificate file, if one is present.
So, that doesn't help me. I need that private key too.
I basically need to recreate the OpenSSL command line tool operation for going PEM>PFX, but in code.
Is there an easier way to do this?
You could use BouncyCastle (assuming C#, because you mentioned .NET).
Let's say localhost.pem
here contains both the certificate and the private key, something like this should work:
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
namespace TestApplication
{
class Program
{
static void Main(string[] args)
{
StreamReader sr = File.OpenText("localhost.pem");
IPasswordFinder passwordFinder = new PasswordStore("testtest".ToCharArray());
PemReader pemReader = new PemReader(sr, passwordFinder);
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
X509CertificateEntry[] chain = new X509CertificateEntry[1];
AsymmetricCipherKeyPair privKey = null;
object o;
while ((o = pemReader.ReadObject()) != null)
{
if (o is X509Certificate)
{
chain[0] = new X509CertificateEntry((X509Certificate)o);
}
else if (o is AsymmetricCipherKeyPair)
{
privKey = (AsymmetricCipherKeyPair)o;
}
}
store.SetKeyEntry("test", new AsymmetricKeyEntry(privKey.Private), chain);
FileStream p12file = File.Create("localhost.p12");
store.Save(p12file, "testtest".ToCharArray(), new SecureRandom());
p12file.Close();
}
}
class PasswordStore : IPasswordFinder
{
private char[] password;
public PasswordStore(
char[] password)
{
this.password = password;
}
public char[] GetPassword()
{
return (char[])password.Clone();
}
}
}
You'll probably need something a bit more subtle for the IPasswordFinder
and if you want to handle certificate chains correctly.
For more advanced features, you may be able to find more details in the BouncyCastle examples.