Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - Export .pfx certificate and import it later as a file

I basically need to export a .pfx certificate as a Base64string, store it in a database and recover it later, converting from Base64string. What I'm using at the moment is the X509Certificate2 class like the following:

To convert it and store in DB the cert64 string:

X509Certificate2 pfx = new X509Certificate2(@"C:\originalcert.pfx", "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.UserKeySet);

string cert64 = Convert.ToBase64String(pfx.RawData);

And get it later from DB (I need to store it as a Base64string):

X509Certificate2 cert = new X509Certificate2();
cert.Import(Convert.FromBase64String(string64cert), "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.UserKeySet);

File.WriteAllBytes(@"C:\copycert.pfx", cert.Export(X509ContentType.Pfx, "password"));

And it returns true when I compare C:\originalcert.pfx and C:\copycert.pfx using:

X509Certificate2.Equals

For the application I'm running that requires a certificate to work properly, I sometimes get an error with some different .pfx certificates provided to me that I use to work around importing/installing to the machine and exporting it via web browser, creat a new .pfx file and voilà.

Using the copycert.pfx file gives me the same error but when I try to install copycert.pfx through the file or import it using a web browser I get: "The import was successful" message, but can't find the installed certificate under the "Personal" tab as I would if I installed the original originalcert.pfx.

Also, it is important that I export from a .pfx file and import it later to a .pfx file.

What am I doing wrong/is missing in the code export/import?

like image 979
Wesley Kalatai Avatar asked Jan 18 '17 18:01

Wesley Kalatai


1 Answers

Your solution doesn't ever work in a manner you describe. Here is why:

string cert64 = Convert.ToBase64String(pfx.RawData);

this line converts only public part of the certificate. No private key information is ever stored in RawData property. This means that you can't restore original PFX from this string. What you really should do is to read contents of the file and convert it to Base64 string without touching X509Certificate2 class. Replace first two lines of posted code with these two:

Byte[] rawCert = File.ReadAllBytes(@"C:\originalcert.pfx");
String cert64 = Convert.ToBase64String(bytes);

PFX certificates support only pure binary encoding (i.e. PFX cannot be stored in PEM format), so just read raw bytes and convert them.

var cert = new X509Certificate2();
cert.Import(Convert.FromBase64String(string64cert), "password", 
    X509KeyStorageFlags.Exportable | 
    X509KeyStorageFlags.PersistKeySet | 
    X509KeyStorageFlags.UserKeySet);

this command only imports certificate to an X509Certificate2 object and installs private key to CSP specified in PFX (or to default CSP if no provider information is stored in PFX). In order to install it to personal store, you need to do that:

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Certificates.Add(cert);
store.Close();

starting with .NET 4.6, X509Store implements IDisposable, so you should use using clause to dispose the object:

using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) {
    store.Open(OpenFlags.ReadWrite);
    store.Add(cert);
}

Note that the code above is necessary only to install certificate to certificate store. In order to restore it from database to PFX file, just save binary data to a file:

Byte[] rawCert = Convert.FromBase64String(string64cert);
File.WriteAllBytes(@"C:\copycert.pfx");

Summary

Just to summarize all written. To convert PFX to Base64 string:

Byte[] rawCert = File.ReadAllBytes(@"C:\originalcert.pfx");
String cert64 = Convert.ToBase64String(bytes);

to restore PFX from Base64 string and save to a file:

Byte[] rawCert = Convert.FromBase64String(string64cert);
File.WriteAllBytes(@"C:\copycert.pfx");
like image 187
Crypt32 Avatar answered Oct 26 '22 06:10

Crypt32