79

I'm trying use self-signed certificate (c#):

X509Certificate2 cert = new X509Certificate2(
    Server.MapPath("~/App_Data/myhost.pfx"), "pass");

on a shared web hosting server and I got an error:

System.Security.Cryptography.CryptographicException: An internal error occurred.

stack trace ends with

System.Security.Cryptography.CryptographicException.
    ThrowCryptogaphicException(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) +237
System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(
    String fileName, String password) +131

On my dev machine it loads ok. The reason I load *.pfx not a *.cer file because I need a private key access (cer file loads Ok). I made pfx on my dev mochine like that:

makecert -r -n "CN=myhost.com, E=admin@myhost.com" -sky exchange -b 01/01/2009
    -pe -sv myhost.pvk myhost.cer
<b>pvk2pfx</b> -pvk myhost.pvk -spc myhost.cer -pfx myhost.pfx -po pass</code>

I am using version v5.131.3790.0 of makecert

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • Perhaps this article can help: http://www.codeproject.com/KB/WCF/wcfcertificates.aspx – Emmanuel Jun 06 '11 at 08:56
  • I was getting the error message `the system cannot find the file specified`. The answer by @Randy Levy worked for me! – Jess Jul 14 '15 at 19:17

2 Answers2

147

Use the local computer store for the private key:

X509Certificate2 cert = new X509Certificate2("myhost.pfx", "pass",
    X509KeyStorageFlags.MachineKeySet);

MachineKeySet is described as "private keys are stored in the local computer store rather than the current user store". The default with no flags is to place in the user store.

Even though you are reading the certificate from disk and storing it in an object the private keys are still stored in the Microsoft Cryptographic API Cryptographic Service Provider key database. On the hosting server the ASP.NET process does not have permission to access the user store.

Another approach (as per some comments below) is to modify the IIS Configuration or App Pool identity -- which do work. However, this assumes that there is access to these configuration items which may not be the case (e.g. in a shared hosting environment).

Randy Levy
  • 22,566
  • 4
  • 68
  • 94
  • 3
    yes it helps, thanks. could you explain why? docs says nothing helpful. –  Aug 28 '09 at 07:07
  • 2
    You saved my day. Oddly enough, it worked on my machine before upgrading the solution to .NET 4.0 – Marc Climent Nov 09 '10 at 16:03
  • 1
    Indeed, all needed to do was set the X509KeyStorageFlags.MachineKeySet parameter. It's really sad that the exception thrown simply states "An internal error occurred." Not very helpful. – Nicholi Oct 12 '11 at 21:06
  • 2
    You can also add more privileges on the private key to the account assigned to the app pool. Or change the app pool identity to "Local Service". – guzart Dec 19 '11 at 16:53
  • 1
    And for a faster fix/workaround check: http://stackoverflow.com/questions/9951729/x509certificate-constructor-exception – Ciprian Teiosanu Oct 02 '13 at 08:36
  • thanks!! I needed to add the MachineKeySet. So my settings are: X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet – Fabian Feb 23 '17 at 14:35
  • @Randy Levy, am facing similar challenges when i run the project on my development machine everything works fine. But once i deploy to my hosting server(i.e. Shared hosting) i get internal server error; even if i add X509KeyStorageFlags.MachineKeySet parameter. Still won't work on shared hosting. – Alexander Nana Owusu Dec 16 '17 at 08:40
  • 1
    I know this is very old, but this worked for me on an ASP.NET web server for Apple Push Notifications. Oddly enough, another ASP.NET app on the same server using the same code worked fine without using this tip, and I have been working for days trying to get Push Notifications to work on my other application. I found this post and tried it out fully expecting it to end up as just another failed try, but it worked! Thanks a lot! – Bill Norman Feb 01 '19 at 21:09
13

I tried Randy's solution of changing it to MachineKeySet, but then got the error message:

"key not valid for use in specified state"

So after a little googling around I found a post that suggested changing it to:

var certificate = new X509Certificate2(certKeyFilePath, passCode, 
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet |       
X509KeyStorageFlags.PersistKeySet );

and this sorted out my issues.

I haven't yet tried the suggestion to change the setting app pool setting in the IIS configuration. To do this go to the Advanced Settings for your site's app pool then set "load user profile" to true. When this setting is false, the key containers aren't accessible apparently.

Myke Black
  • 1,299
  • 15
  • 15