Azure loading X509Certificate2 from byte[] cannot find file specified

52 views Asked by At

I have an Azure Function App from which I'm trying to pull a certificate from Azure Key Vault. My code is as follows:

    private X509Certificate2 GetCertificate(
        CertificateClient certificateClient,
        SecretClient secretClient,
        string certificateName)
    {
        KeyVaultCertificateWithPolicy certificate = certificateClient.GetCertificate(certificateName);

        // Return a certificate with only the public key if the private key is not exportable.
        if (certificate.Policy?.Exportable != true)
        {
            return new X509Certificate2(certificate.Cer);
        }

        // Parse the secret ID and version to retrieve the private key.
        string[] segments = certificate.SecretId.AbsolutePath.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
        if (segments.Length != 3)
        {
            throw new InvalidOperationException($"Number of segments is incorrect: {segments.Length}, URI: {certificate.SecretId}");
        }

        string secretName = segments[1];
        string secretVersion = segments[2];

        KeyVaultSecret secret = secretClient.GetSecret(secretName, secretVersion);
        
        if ("application/x-pkcs12".Equals(secret.Properties.ContentType, StringComparison.InvariantCultureIgnoreCase))
        {
            byte[] pfx = Convert.FromBase64String(secret.Value);

            // Exception thrown here
            return new X509Certificate2(pfx);
        }

        throw new NotSupportedException($"Only PKCS#12 is supported. Found Content-Type: {secret.Properties.ContentType}");
    }
}

I've set the access permission in Key Vault to all and added additional logging to the function. I can see that it runs to the line that I've commented, and it the content of pfx exactly matches the certificate which I added to Key Vault.

When trying to create an instance of X509Certificate2 I get the exception The system cannot find the file specified. with no information about what file it's referencing.

The strange part is that if run locally with my personal Azure credentials, I get the exact same byte array back and I don't get that exception.

1

There are 1 answers

0
Pravallika KV On

The system cannot find the file specified.

To resolve this error, add the application setting WEBSITE_LOAD_USER_PROFILE=1 in the Function App=>Settings=>Configuration/Environment Variables. Refer GitHub article.

Set the key vault reference as the value of the setting in the Function App.

@Microsoft.KeyVault(SecretUri=https://<keyvaultname>.vault.azure.net/certificates/<your_Certificate_name>/)

Application Settings of my function app:

enter image description here

  • Created Azure Key vault and provided the required permissions to the Service Principal.

enter image description here

  • I have created a X509 Certificate and imported in Azure Key Vault.
  • Able to retrieve the certificate from the Azure Key Vault using below code.

Code Snippet:

[FunctionName("Function1")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
    ILogger log)
{
    string keyVaultUrl = "https://<keyvault>.vault.azure.net/";
    string certificateName = "kpcert";
    X509Certificate2 certificate ;

    var certificateClient = new CertificateClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
    var secretClient = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential());

     certificate = await GetCertificate(certificateClient, secretClient, certificateName);

    log.LogInformation("Certificate retrieved successfully.");

    return new OkObjectResult(certificate);
}

private static async Task<X509Certificate2> GetCertificate(
    CertificateClient certificateClient,
    SecretClient secretClient,
    string certificateName)
{
    KeyVaultCertificateWithPolicy certificate = await certificateClient.GetCertificateAsync(certificateName);

    if (certificate.Policy?.Exportable != true)
    {
        return new X509Certificate2(certificate.Cer);
    }

    string[] segments = certificate.SecretId.AbsolutePath.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
    if (segments.Length != 3)
    {
        throw new InvalidOperationException($"Number of segments is incorrect: {segments.Length}, URI: {certificate.SecretId}");
    }

    string secretName = segments[1];
    string secretVersion = segments[2];

    KeyVaultSecret secret = await secretClient.GetSecretAsync(secretName, secretVersion);

    if ("application/x-pkcs12".Equals(secret.Properties.ContentType, StringComparison.InvariantCultureIgnoreCase))
    {
        byte[] pfx = Convert.FromBase64String(secret.Value);
        return new X509Certificate2(pfx);
    }

    throw new NotSupportedException($"Only PKCS#12 is supported. Found Content-Type: {secret.Properties.ContentType}");
}

Console output:

enter image description here

Local Response:

enter image description here

Portal: enter image description here

enter image description here