简体   繁体   中英

How to serialize and deserialize a PFX certificate in Azure Key Vault?

I have a bunch of strings and pfx certificates, which I want to store in Azure Key vault, where only allowed users/apps will be able to get them. It is not hard to do store a string as a Secret, but how can I serialize a certificate in such way that I could retrieve it and deserialize as an X509Certificate2 object in C#?

I tried to store it as a key. Here is the Azure powershell code

$securepfxpwd = ConvertTo-SecureString -String 'superSecurePassword' -AsPlainText -Force
$key = Add-AzureKeyVaultKey -VaultName 'UltraVault' -Name 'MyCertificate' -KeyFilePath 'D:\Certificates\BlaBla.pfx' -KeyFilePassword $securepfxpwd

But when I tried to get it with GetKeyAsync method, I couldn't use it.

Here's a PowerShell script for you. Replace the file path, password, vault name, secret name.

$pfxFilePath = 'C:\mycert.pfx'
$pwd = '123'
$flag = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection 
$collection.Import($pfxFilePath, $pwd, $flag)
$pkcs12ContentType = [System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12
$clearBytes = $collection.Export($pkcs12ContentType)
$fileContentEncoded = [System.Convert]::ToBase64String($clearBytes)
$secret = ConvertTo-SecureString -String $fileContentEncoded -AsPlainText –Force
$secretContentType = 'application/x-pkcs12'
Set-AzureKeyVaultSecret -VaultName 'myVaultName' -Name 'mySecretName' -SecretValue $Secret -ContentType $secretContentType

This is a common question, so we are going to polish this up and release as a helper.

The script above strips the password because there's no value in having a password protected PFX and then storing the password next to it.

The original question asked how to retrieve the stored PFX as an X509Certificate2 object. Using a Base64 process similar to that posted by Sumedh Barde above (which has the advantage of stripping the password), the following code will return a X509 object. In a real application, the KeyVaultClient should be cached if you're retrieving multiple secrets, and the individual secrets should also be cached.

public static async Task<X509Certificate2> GetSecretCertificateAsync(string secretName)
{
    string baseUri = @"https://xxxxxxxx.vault.azure.net/secrets/";

    var provider = new AzureServiceTokenProvider();
    var client =  new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(provider.KeyVaultTokenCallback));
    var secretBundle = await client.GetSecretAsync($"{baseUri}{secretName}").ConfigureAwait(false);
    string pfx = secretBundle.Value;

    var bytes = Convert.FromBase64String(pfx);
    var coll = new X509Certificate2Collection();
    coll.Import(bytes, "certificatePassword", X509KeyStorageFlags.Exportable);
    return coll[0];
}

Here is how I solved this. First, convert your PFX file to a base64 string. You can do that with these two simple PowerShell commands:

$fileContentBytes = get-content 'certificate.pfx' -Encoding Byte
[System.Convert]::ToBase64String($fileContentBytes) | Out-File 'certificate_base64.txt'

Create a secret in Azure Key Vault via the Azure Portal . Copy the certificate base64 string that you created previously and paste it in the secret value field in your Azure Key Vault via the Azure Portal . Then simply call the Azure Key Vault from the code to get the base64 string value and convert that to a X509Certificate2 :

private async Task<X509Certificate2> GetCertificateAsync()
{
    var azureServiceTokenProvider = new AzureServiceTokenProvider();
    var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
    var secret = await keyVaultClient.GetSecretAsync("https://path/to/key/vault").ConfigureAwait(false);
    var pfxBase64 = secret.Value;
    var bytes = Convert.FromBase64String(pfxBase64);
    var coll = new X509Certificate2Collection();
    coll.Import(bytes, "certificatePassword", X509KeyStorageFlags.Exportable);
    return coll[0];
}

See the following answer, which describes how to do this using the latest .NET Azure SDK client libraries:

How can I create an X509Certificate2 object from an Azure Key Vault KeyBundle

Here is the script for uploading pfx certificate in python using azure cli

azure keyvault secret set --vault-name <Valut name> --secret-name <Secret Name> --value <Content of PFX file>

Getting the content of PFX file in python

fh = open(self.getPfxFilePath(), 'rb')
    try:
        ba = bytearray(fh.read())
        cert_base64_str = base64.b64encode(ba)
        password = self.getPassword()
        json_blob = {
            'data': cert_base64_str,
            'dataType': 'pfx',
            'password': password
        }
        blob_data= json.dumps(json_blob)
        content_bytes= bytearray(blob_data)
        content = base64.b64encode(content_bytes)
        return content
    finally:
        fh.close
    fh.close()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM