6

I am currently working on an authentication server developed in C #, this one is hosted on an azure function app, and I use a KeyVault where my secrets are stored. My problem is the following, in my keyvault, I store a certificate (certificate + private key) and when I retrieve it in my code, but the private key is not returned. if I test the following method: HasPrivateKey the code returns false ... but if i use the same .pfx in localy the code return me true ... my code:

 var client = new CertificateClient(vaultUri: new Uri("https://diiage2p1g3chest.vault.azure.net/"),credential: new DefaultAzureCredential());
         KeyVaultCertificate kcertificate = client.GetCertificate("try");
         var cert_content = kcertificate.Cer;
       X509Certificate2  certificate = new X509Certificate2(cert_content, "password", X509KeyStorageFlags.EphemeralKeySet);

any idea where the problem comes from?

Damien PAYET
  • 161
  • 2
  • 9

4 Answers4

15

CertificateClient has a method that returns a certificate with private key, but it's not obvious that's what it does.

From CertificateClient.DownloadCertificate:

Because Cer contains only the public key, this method attempts to download the managed secret that contains the full certificate. If you do not have permissions to get the secret, RequestFailedException will be thrown with an appropriate error response. If you want an X509Certificate2 with only the public key, instantiate it passing only the Cer property. This operation requires the certificates/get and secrets/get permissions.

So just refactor your code to use DownloadCertificate to get a cert with the private key.

var client = new CertificateClient(new Uri("https://diiage2p1g3chest.vault.azure.net/"),  new DefaultAzureCredential()); 
X509Certificate2 certificate = client.DownloadCertificate("try");
Daniel Gimenez
  • 18,530
  • 3
  • 50
  • 70
4

The simplest way to get the full bytes of a certificate with its private information from keyvault is this. Please note you need permission to get secrets in your client id.

You need the following packages:

Azure.Identity
Azure.Security.KeyVault.Secrets

The following are deprecated:

Microsoft.IdentityModel.Clients.ActiveDirectory
Microsoft.Azure.KeyVault

Code:

using System;
using System.Threading.Tasks;
using Azure;
using Azure.Identity;
using System.Security.Cryptography.X509Certificates;
using Azure.Security.KeyVault.Secrets;

...

public async Task<X509Certificate2> GetCertificate(string certificateName,string clientId, string clientSecret, string keyVaultAddress, string tenantId)
        {
            ClientSecretCredential clientCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var secretClient = new SecretClient(new Uri(keyVaultAddress), clientCredential);
            var response = await secretClient.GetSecretAsync(certificateName);
            var keyVaultSecret = response?.Value;
            if(keyVaultSecret != null)
            {
                var privateKeyBytes = Convert.FromBase64String(keyVaultSecret.Value);
                return new X509Certificate2(privateKeyBytes);
            }
            return null;
        }
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
Ruben G.L
  • 41
  • 2
0
 var _keyVaultName = $"VAULTURL";
        var secretName = "CERTIFICATENAME";
        var azureServiceTokenProvider = new AzureServiceTokenProvider();
        var _client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
        var secret = _client.GetSecretAsync(_keyVaultName, secretName);
        var privateKeyBytes = Convert.FromBase64String(secret.Result.Value);
        certificate = new X509Certificate2(privateKeyBytes, string.Empty);

i solve my probleme like that :)

Damien PAYET
  • 161
  • 2
  • 9
0
        X509Certificate2 certificate;
        ClientSecretCredential clientCredential = new ClientSecretCredential(TenantId,ClientId,ClientSecret);
        var secretClient = new SecretClient(new Uri(KeyVaultUrl), clientCredential);
        var response = await secretClient.GetSecretAsync(individualEnrollment.DeviceId.Replace("-", ""));
        var keyVaultSecret = response?.Value;
        var privateKeyBytes = Convert.FromBase64String(keyVaultSecret.Value);
        certificate = new X509Certificate2(privateKeyBytes);

        
        using (var security = new SecurityProviderX509Certificate(certificate))
        using (var transport = new ProvisioningTransportHandlerAmqp(TransportFallbackType.TcpOnly))
        {
            ProvisioningDeviceClient provClient =
                ProvisioningDeviceClient.Create(GlobalDeviceEndpoint, Scope, security, transport);

            var deviceClient = await ProvisionX509Device(provClient, security);
            
        }
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
lucky
  • 1
  • Hello, please see https://meta.stackoverflow.com/editing-help Thanks! – Eric Aya Nov 24 '22 at 13:33
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Jeremy Caney Nov 27 '22 at 01:36