3
votes

I'm using function app to get key vault certificate,but get the exception as below:

The system can not find the file specified
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData)
at DWP.CDA.FunctionApp.Utils.CertificateHelper.GetKeyVaultCertificate(String keyvaultName, String name)
at DWP.CDA.FunctionApp.ProcessRequest.Run(JObject eventGridEvent, TraceWriter log)

It works well in my local visual studio as I use my own account to get azure service authentication.I give the full access to my account and give get access to function app in key vault access policies

Here is my code how to get certificate:

internal static X509Certificate2 GetKeyVaultCertificate(string keyvaultName, string name)
        {
            var serviceTokenProvider = new AzureServiceTokenProvider();
            var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(serviceTokenProvider.KeyVaultTokenCallback));

            // Getting the certificate
            var secret = keyVaultClient.GetSecretAsync("https://" + keyvaultName + ".vault.azure.net/", name);

            // Returning the certificate
            return new X509Certificate2(Convert.FromBase64String(secret.Result.Value));
        }
1
Could you please have a try to use "var certificate = new X509Certificate2(privateKeyBytes, (string)null);" ? - Hury Shen

1 Answers

3
votes

I use the same code with yours' and it doesn't show the error message(both in local or azure portal). I edit it in visual studio, the code shown as below:

namespace FunctionApp7
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var serviceTokenProvider = new AzureServiceTokenProvider();
            var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(serviceTokenProvider.KeyVaultTokenCallback));

            // Getting the certificate
            var secret = keyVaultClient.GetSecretAsync("https://***.vault.azure.net/", "***");


            var certificate = new X509Certificate2(Convert.FromBase64String(secret.Result.Value));

            log.LogInformation(certificate.ToString());

            return new OkObjectResult("success");
        }
    }
}

It works fine in visual studio and also works fine when I deploy it from visual studio to azure portal.

Here is a post which mentioned a solution you can also have a try. The post tell us

If you include this code in an ASP.NET Core project and run it locally, it will work as expected. But if you deploy it to Azure (as a Web App or Azure Function), you will get this exception: The system cannot find the file specified

The solution is:

var certificate = new X509Certificate2(Convert.FromBase64String(secret.Value), 
                    (string)null, 
                    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

Hope it helps~