Akash Anup
Akash Anup

Reputation: 1

Key and Secret objects aren't found while generating a certificate in Azure KeyVault

Use Case: Authenticate an AAD App via a certificate.

I've created a PKCS12 certificate in Azure KeyVault and when I am using it to authenticate my AAD App I'm getting this exception:

"Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException" at DownloadCertificateAsync method.

After some debugging, I found that when a certificate is created in Azure KeyVault, three objects are created -

  1. Certificates: Contains the public key and metadata.
  2. Keys: Represents the private key associated with the certificate.
  3. Secrets: Contains the certificate value, which can be retrieved in PFX or PEM format.

In the certificate, I am able to see the KeyIdentifierUrl and SecretIdentifierUrl but in their corresponding Keys and Secrets section I don't find any matching object.

In the below code snippet, in my opinion, DownloadCertificateAsync method, after fetching certificate when its secret is fetched for private key, the object might not be found and hence an exception is thrown.

Could someone please let me know what is missing or what wrong am I doing and how to resolve it?

Uri kvUri = new Uri($"https://{keyVaultName}.vault.azure.net");
DefaultAzureCredential credential = new DefaultAzureCredential();
CertificateClient certificateClient = new CertificateClient(kvUri, credential);
KeyVaultCertificateWithPolicy certificate = await certificateClient.GetCertificateAsync(certificateName);

if (certificate.Policy?.Exportable != true)
{
    throw new KeyVaultException($"Error: certificate \"{certificateName}\" is not exportable.");
}
else if (certificate.Policy?.KeyType != CertificateKeyType.Rsa)
{
    throw new KeyVaultException($@"Error: certificate type ""{certificate.Policy?.KeyType}"" cannot be used to locally encrypt and decrypt.");
}

X509Certificate2 x509Certificate2 = new X509Certificate2(certificate.Cer, "", X509KeyStorageFlags.Exportable);

if (!x509Certificate2.HasPrivateKey)
{
    x509Certificate2 = new X509Certificate2(certificate.Cer, "", X509KeyStorageFlags.MachineKeySet);
    if (!x509Certificate2.HasPrivateKey)
    {
        x509Certificate2 = new X509Certificate2(certificate.Cer, "", X509KeyStorageFlags.PersistKeySet);
        if (!x509Certificate2.HasPrivateKey)
        {
            try
            {
**                x509Certificate2 = await certificateClient.DownloadCertificateAsync(certificateName);**
            }
            catch (Exception ex)
            {
                throw new KeyVaultException($"Error downloading certificate with name \"{certificateName}\".", ex);
            }
        }
    }
}

var app = ConfidentialClientApplicationBuilder.Create(clientId)
                .WithAuthority(authority)
                .WithCertificate(x509Certificate2)
                .Build();

Note: In my code, I have verified that the certificate is Exportable and can be Encrypted/Decrypted.

Upvotes: 0

Views: 85

Answers (1)

Pravallika KV
Pravallika KV

Reputation: 8400

  • Validate the Certificate Name and also make sure the certificate is not corrupted.
  • Ensure you have required permissions (eg: Key Vault Administrator) to access and download the certificate.

I have tried the same code by adding exception handling and able to run without issues:

using Azure.Identity;
using Azure.Security.KeyVault.Certificates;
using Microsoft.Identity.Client;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;

var certificateName = "certificate_name";
var clientId = "<client_id>";
var tenantId = "<tenant_id>";
var authority = "https://login.microsoftonline.com/<tenant_id>";
var keyVaultName = "kpvault166";
Uri kvUri = new Uri($"https://{keyVaultName}.vault.azure.net");
DefaultAzureCredential credential = new DefaultAzureCredential();
CertificateClient certificateClient = new CertificateClient(kvUri, credential);
KeyVaultCertificateWithPolicy certificate = await certificateClient.GetCertificateAsync(certificateName);

X509Certificate2 x509Certificate2 = new X509Certificate2(certificate.Cer, "", X509KeyStorageFlags.Exportable);

if (!x509Certificate2.HasPrivateKey)
{
    x509Certificate2 = new X509Certificate2(certificate.Cer, "", X509KeyStorageFlags.MachineKeySet);
    if (!x509Certificate2.HasPrivateKey)
    {
        x509Certificate2 = new X509Certificate2(certificate.Cer, "", X509KeyStorageFlags.PersistKeySet);
        if (!x509Certificate2.HasPrivateKey)
        {
            try
            {
                x509Certificate2 = await certificateClient.DownloadCertificateAsync(certificateName);
                Console.WriteLine(x509Certificate2);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
           
        }
    }
}

var app = ConfidentialClientApplicationBuilder.Create(clientId)
                .WithAuthority(authority)
                .WithCertificate(x509Certificate2)
                .Build();

Console Response:

enter image description here

Upvotes: 0

Related Questions