title: .NET Core 2.2, Azure Web API new X509Certificate2 "The system cannot find the file specified" and "access denied"
body: <p>My Azure Web API loads a certificate stored as a secret in Key Vault and then attempts to create a new certificate from a byte array.  Running locally <em>everything works</em>, but, when deployed to Azure we get <strong>Access Denied</strong> or <strong>The system cannot find the file specified</strong> depending on the KeyStorageFlags passed to the constructor.  The Web API is using .Net Core 2.2</p>
  
  <p>I've been at this for some time reading lots of information related to this but not this specific scenario.</p>
  
  <p>Using MachineKeySet flag:
  <code>certificate = new X509Certificate2(pfxBytes, "",
                              X509KeyStorageFlags.MachineKeySet |
                              X509KeyStorageFlags.Exportable);</code></p>
  
  <p>Exception</p>
  
  <blockquote>
    <p>ex=Access denied,  stack=   at
    Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[]
    rawData, SafePasswordHandle password, PfxCertStoreFlags
    pfxCertStoreFlags)    at
    Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[]
    rawData, String fileName, SafePasswordHandle password,
    X509KeyStorageFlags keyStorageFlags)    at
    System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[]
    rawData, String password, X509KeyStorageFlags keyStorageFlags)</p>
  </blockquote>
  
  <p>Using UserKeySet flag:
                          <code>certificate = new X509Certificate2(pfxBytes, "",
                              X509KeyStorageFlags.UserKeySet |
                              X509KeyStorageFlags.Exportable);</code></p>
  
  <p>Exception</p>
  
  <blockquote>
    <p>ex=The system cannot find the file specified, stack=   at
    Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[]
    rawData, SafePasswordHandle password, PfxCertStoreFlags
    pfxCertStoreFlags)    at
    Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[]
    rawData, String fileName, SafePasswordHandle password,
    X509KeyStorageFlags keyStorageFlags)    at
    System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[]
    rawData, String password, X509KeyStorageFlags keyStorageFlags)</p>
  </blockquote>
  
  <p>I followed the load cert as a secret using this article
  [<a href="https://www.rahulpnath.com/blog/pfx-certificate-in-azure-key-vault/][1]" rel="noreferrer">https://www.rahulpnath.com/blog/pfx-certificate-in-azure-key-vault/][1]</a>
   This doesn't appear to have anything to do with key vault because it loads the secret from Key Vault just fine locally, and, loading in Azure is not where the exception is thrown.  But it might be related to how the certificate is stored?</p>
  
  <p>Here's the full code we're using</p>
  
  <pre><code>private async Task&lt;X509Certificate2&gt; GetSecretCertificateFromKVAPI()
          {
              try
              {
                  var keyVaultName = _configuration["Secrets:KeyVaultName"];
  
                  var keyVaultEndpoint = $"https://{keyVaultName}.vault.azure.net:443/secrets/";
                  var provider = new AzureServiceTokenProvider();
                  var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback));
                  SecretBundle secretRetrieved;
  
                  secretRetrieved = await client.GetSecretAsync($"{keyVaultEndpoint}OdysseyCA");
  
                  var pfxBytes = Convert.FromBase64String(secretRetrieved?.Value);
  
                  //note, must pass an empty password when loading from keyvault in Azure
                  X509Certificate2 certificate;
                  try
                  {
                      // or recreate the certificate directly
                      certificate = new X509Certificate2(pfxBytes, "",
                              X509KeyStorageFlags.MachineKeySet |
                              X509KeyStorageFlags.PersistKeySet |
                              X509KeyStorageFlags.Exportable);
  
                      // alternative, try using import
                      //var coll = new X509Certificate2Collection();
                      //coll.Import(pfxBytes, null, X509KeyStorageFlags.Exportable);
                      //certificate = coll[0];
                  }
                  catch (Exception ex)
                  {
                      _logger.Trace($"create new X509 failed, ex={ex.Message}, stack={ex.StackTrace}");
                      throw;
                  }
  
                  return certificate;
              }
              catch (Exception ex)
              {
                  _logger.Trace($"GetSecretCertificateFromKVAPI threw an exception, ex={ex.Message}, stack = {ex.StackTrace}");
                  throw;
              }
          }
  </code></pre>
  
  <p>In the code you can see we tried using the .import method of the X509Certificate2Collection class to work around this but the results are the same.  We're actively backing up to .Net Core 2.1 and 2.0 to see if this is a new bug and searching for other answers.</p>
  
  <p>How do we get this to work?             </p>
  
  <p>Edit: based on a suggestion in the comments below tried the EphemeralKeySet flag but the exception stack is pretty much the same as others:</p>
  
  <p><code>certificate = new X509Certificate2(pfxBytes, "",
                              X509KeyStorageFlags.EphemeralKeySet |
                              X509KeyStorageFlags.Exportable);</code></p>
  
  <blockquote>
    <p>ex=The system cannot find the file specified, stack =    at
    Internal.Cryptography.Pal.CertificatePal.FilterPFXStore(Byte[]
    rawData, SafePasswordHandle password, PfxCertStoreFlags
    pfxCertStoreFlags)    at
    Internal.Cryptography.Pal.CertificatePal.FromBlobOrFile(Byte[]
    rawData, String fileName, SafePasswordHandle password,
    X509KeyStorageFlags keyStorageFlags)    at
    System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[]
    rawData, String password, X509KeyStorageFlags keyStorageFlags)</p>
  </blockquote>
  
  <p>Can anyone confirm this works with .Net any version? possible core or 2.2 bug?</p>