16

I have a .cer file output from a successful LetsEncrypt certificate request.

I have the original Private Key used to create the Certificate Signing Request (CSR) for LetsEncrypt.

Now we need to programmatically combine these two files into a PFX bundle for IIS using .NET

Since we are trying to to do this programmatically pvk2pfx is not practical, and we would like to avoid openssl if possible.

To demonstrate though, we are trying to replicate this function but using CS .NET instead of pvk2pfx: pvk2pfx.exe -pvk Server.pvk -spc Server.cer -pfx Server.pfx

I have researched exhaustively and here are the possibilities I see:

One method seems to be using X509Certificate2 something like:

// Import the certificate
X509Certificate2 cert = new X509Certificate2("c:\\cert.cer");

// Import the private key
X509Certificate2 cert = new X509Certificate2("c:\\key.pvk");

// Or import the private key - Alternative method
X509DecryptString(token, @"c:\CA.pvk", "mypassword");

// Export the PFX file
certificate.Export(X509ContentType.Pfx, "YourPassword");
File.WriteAllBytes(@"C:\YourCert.pfx", certificateData);

Here are some other methods but all of them seem to omit the part about the Private Key or they require pvk2pfx.exe

Conversion from cert file to pfx file https://stackoverflow.com/a/4797392/3693688

How to create a X509Certificate2 programmatically? http://www.wiktorzychla.com/2012/12/how-to-create-x509certificate2.html

Select, Create and Find X509 Certificates: http://www.wou.edu/~rvitolo06/WATK/Demos/HPCImageRendering/code/ImageRendering/AppConfigure/CertHelper.cs

Cannot export generated certificate with private key to byte array Cannot export generated certificate with a private key to byte array in .NET 4.0/4.5

How to programmatically import a pfx with a chain of certificates into the certificate store. https://stackoverflow.com/a/9152838/3693688

Import .cer and .pvk certificate files programmatically in C# for use with netsh http add sslcert https://gist.github.com/BrandonLWhite/235fa12247f6dc827051

Method to convert cer to pfx cert https://gist.github.com/domgreen/988684


EDIT 1

CryptoGuy suggested we need this link: https://gist.github.com/BrandonLWhite/235fa12247f6dc827051

Does that mean something like this would be good?

Are the CSP parts necessary?

using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;

    var PublicKey = AssemblyUtility.GetEmbeddedFileAsByteArray("Cert.cer");
    var PrivateKey = AssemblyUtility.GetEmbeddedFileAsByteArray("PrivateKey.pvk");
    var certificate = new X509Certificate2(PublicKey, string.Empty, 
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
    var cspParams = new CspParameters
    {
        ProviderType = 1,
        Flags = CspProviderFlags.UseMachineKeyStore,
        KeyContainerName = Guid.NewGuid().ToString().ToUpperInvariant()
    };
    var rsa = new RSACryptoServiceProvider(cspParams);

    rsa.ImportCspBlob(ExtractPrivateKeyBlobFromPvk(PrivateKey));
    rsa.PersistKeyInCsp = true;
    certificate.PrivateKey = rsa;

    certificate.Export(X509ContentType.Pfx, "YourPassword");
    File.WriteAllBytes(@"C:\YourCert.pfx", certificateData);
Cœur
  • 37,241
  • 25
  • 195
  • 267
Marcus
  • 675
  • 2
  • 8
  • 24
  • 1
    One of your links (https://gist.github.com/BrandonLWhite/235fa12247f6dc827051) looks like the right choice for you. – Crypt32 Feb 15 '16 at 18:15
  • Yes, CSP parts are mandatory, because it is the only supported way to work with asymmetric cryptography in Windows. In short, you have to load a private key file (which is either, PKCS#1, PKCS8 or whatever else) to a CSP and associate it with an X509Certificate2 object. – Crypt32 Feb 15 '16 at 19:04
  • Interesting, thanks! Looks like that might be what we were missing before. Does the certificate.Export(X509ContentType.Pfx...) part look right? I have copied that from another source and removed the netsh and sCertHash parts as I think we don't need these if we are just saving to a pfx file? – Marcus Feb 15 '16 at 19:20
  • netsh part is another story (you don't need this). All you need is to get the `ExtractPrivateKeyBlobFromPvk` method (I don't know where to get it) which is used in the code. I would suspect that his code just converts PKCS#1/PKCS#8 private key to CryptoAPI private key blob: https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx – Crypt32 Feb 15 '16 at 20:03
  • Something like this maybe? https://www.sysadmins.lv/blog-en/how-to-convert-pem-file-to-a-cryptoapi-compatible-format.aspx – Marcus Feb 15 '16 at 20:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/103530/discussion-between-marcus-and-cryptoguy). – Marcus Feb 15 '16 at 20:42
  • What is `ExtractPrivateKeyBlobFromPvk`? keep seeing this same snippet in other articles but no mentioning of where/what `ExtractPrivateKeyBlobFromPvk` is. – mwilson Apr 23 '19 at 17:39
  • Should the second last line be added with: "byte[] certificateData =" ? – Raymond A. Nov 09 '20 at 16:07

1 Answers1

1

CryptoGuy's answer was really helpful and pointed us in the right direction.

We were still struggling to import a Binary DER file but this code fixed that:

var oc = OpenSSL.X509.X509Certificate.FromDER(bio); 

These pages were useful:

https://github.com/openssl-net/openssl-net/blob/master/ManagedOpenSsl/X509/X509Certificate.cs

https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.rawdata

Thanks all for your help :)

Marcus
  • 675
  • 2
  • 8
  • 24