How I got burned today …
I needed to write a simple SAML 1.1 provider that would generate a SAML token and sign it using a .pfx certificate.
So I wrote this code in my MVC4 Controller …
var cert = new X509Certificate2(pfxFile, "myPassword"); var privateKey = cert.PrivateKey;
Used the private key to sign the token, ran it locally with no issue. However, once I published the site to Windows Azure Websites I get this error.
[CryptographicException: The system cannot find the file specified. ] System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +33 System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromFile(String fileName, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx) +0 System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags) +218 System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password) +63 System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password) +58 WAWSPfxTest.Controllers.HomeController.Index() +180
I confirmed that the file did in fact exist.
What happened ??
Well it turns out that when you load certificates the system will use a local directory to store the key (??)
The default location for the key is the under the local user profile, and with Windows Azure Websites, there is no local user profile directory.
Key Storage Flags to the rescue
With some trial and error I found that the MachineKeySet flag worked on my Windows Azure Website. So with a quick change to the code it was working again.
var cert = new X509Certificate2(pfxFile, "myPassword", X509KeyStorageFlags.MachineKeySet); var privateKey = cert.PrivateKey;
I hope this helps someone.