Frequently Asked Questions About HGS Certificates


The Host Guardian Service uses public key cryptography extensively to protect shielded VMs from attackers. Any time certificates with public-private key pairs come into play, there are bound to be many questions about how to properly set up and protect those certificates. This blog hopes to clarify the most common questions our team is asked about certificate usage in HGS.

 

Q: What purpose does each of the HGS certificates serve?

A: There are 6 different types of certificates used by HGS.

  • Encryption certificate: used to encrypt and decrypt the key protector, which itself contains the symmetric key that encrypts the virtual TPM of a shielded VM at rest.
  • Signing certificate: used to digitally sign the key protector to ensure its authenticity.
  • Communications certificate: used to digitally sign the metadata document provided to tenants for use in the Shielding Data File wizard.
  • Attestation signer certificate: used to sign health certificates issued by HGS to Hyper-V hosts that have successfully completed an attestation request. Hyper-V hosts will present the health certificate when they need to start up a shielded VM, allowing HGS to ensure the certificate was signed by a trusted attestation signer certificate to verify authenticity.
  • HTTPS (SSL/TLS) certificate: an optional certificate used to encrypt HTTP communications between Hyper-V hosts and the HGS server. While the key protector is always encrypted when transmitted, HTTPS may help you comply with regulatory requirements to protect all data at the transport layer.
  • Dump encryption certificate: an optional certificate used to encrypt memory dumps on Hyper-V hosts to protect sensitive information in shielded VMs. By default, HGS disallows all dumps, but if you choose to enable them, you can ensure Hyper-V hosts are encrypting the dumps with a trusted certificate known to HGS.

 

Q: Which certificates do I need to provide?

A: Of the above 6 certificates, the only required certificates during installation of HGS are the signing and encryption certificate. The communications certificate will re-use the signing certificate by default, and the attestation signer certificate is automatically generated and maintained by HGS (you'll see it in the local machine's certificate store with the subject name "Microsoft Remote Attestation Service").

If you choose to use HTTPS on HGS or dump encryption on Hyper-V hosts, you will need to obtain certificates for these purposes and provide that information to HGS as well.

 

Q: How do I find which certificates are registered with HGS?

A: To find the signing and encryption certificates registered with HGS, run Get-HgsKeyProtectionCertificate on the HGS server. The communications certificate configuration can be retrieved with Get-HgsKeyProtectionConfiguration. By default, the signing certificate is re-used as your communications certificate, so there's no need to worry if you see it twice.

 

Q: Should I add my certificate to HGS using a PFX file or by thumbprint?

A: Unless you are using a certificate with a private key stored in a hardware security module, you should add your certificate to HGS using a password protected PFX file that contains the private key. This will allow HGS to replicate the certificate to other HGS nodes and automatically manage the permissions for you.

If you cannot export your certificate with its private key to a PFX file (as is the case with HSM-backed certificates, where the private key never leaves the HSM device), you will have to add the certificate to HGS using its thumbprint. This requires you to install the certificate and key storage provider on each HGS node according to your manufacturer's instructions and ensure that the HGS group managed service account has access to use the private key.

 

Q: Do I have to use a hardware security module for the signing and encryption certificates?

A: Hardware Security Modules (HSMs) can help prevent theft and misuse of certificate private keys. HSMs may help you meet compliance requirements or provide additional assurances that your certificates cannot be exported and used maliciously on other machines. HGS does not require the use of an HSM, but supports any HSM that uses a Key Storage Provider to communicate between Windows and the HSM.

 

Q: Does HGS support "bring your own key" scenarios?

A: Yes, HGS allows you to configure more than one signing and encryption certificate. This is ideal if your VM owners want to use encryption and signing keys unique to them. To add additional certificates, use Add-HgsKeyProtectionCertificate on an HGS server. As you may have guessed, Remove-HgsKeyProtectionCertificate will help you remove certificates if your VM owners no longer use your hosting infrastructure.

 

Q: Which certificates are included in the HGS metadata document?

A: The metadata document (obtained at http://<hgs>/KeyProtection/service/metadata/2014-07/metadata.xml) contains the primary signing and encryption certificates along with their public keys, and is signed by the communications certificate. This document needs to be provided to your VM owners when they are running the shielding data file wizard to authorize your HGS to decrypt their VMs' TPMs. You can find the primary signing and encryption certificates with Get-HgsKeyProtectionCertificate -IsPrimary $true and change them with Set-HgsKeyProtectionCertificate.

 

Q: I want to use certificates issued by a third party or enterprise certificate authority. How should I configure the certificate template?

A: For encryption, signing and communications certificates, refer to the table of required certificate properties in our documentation. HTTPS certificates can be issued in any format supported by Internet Information Services 10, but should follow the subject name requirements explained in the HGS HTTPS documentation.

 

Q: What happens when my certificates expire?

A: If your encryption or signing certificate expires, don't panic! Certificates are only validated once during the lifetime of a shielded VM: when the HGS metadata is added in the shielding data file wizard or Import-HgsGuardian PowerShell cmdlet. Existing shielded VMs and new VMs created using the same encryption keys will continue to work the same after the certificate expires. Do not renew the certificates unless you are sure that doing so will not change the key pair. If the keys change, existing shielded VMs will be unable to decrypt their vTPM state and, therefore, will not start.

Instead, you should create new signing and encryption certificates and add them to HGS as additional certificates, and mark them as primary certificates (see Add-HgsKeyProtectionCertificate and Set-HgsKeyProtectionCertificate). Leave the expired certificates in HGS so that existing VMs can continue to boot using those certificates. New VMs created using metadata obtained after the HGS certificates were updated will use the new (valid) certificates.

Sidebar: The recommendation to not renew your signing and encryption certificates probably makes your PKI experts' hair stand on end. To help calm their nerves, offer them a cup of tea and think about how these certificates are used. They are intended for long-term protection of the keys that encrypt the virtual TPM for a shielded VM. There's no telling how long your VMs will run. A VM could run for minutes, days, or years. The keys originally used to wrap the VM's transport key (the symmetric key that encrypts the vTPM contents) must remain available throughout the lifetime of the VM, thus you should not remove or renew the keys until you're 100% sure no shielded VMs rely on it. Also, remember that VM checkpoints and backups are bound to the encryption keys used at the time the snapshot was taken, so even if you're not using the keys today, you may want to keep them around in case a VM is restored to an earlier state.

The communications certificate provides additional assurances to advanced users that the HGS metadata document has not been modified during transit. The shielding data file wizard does not validate the communications certificate, so there is little risk if the communications certificate expires unless you are manually validating the XML document signature. You can update the communications certificate at any time without impacting existing VMs using Set-HgsKeyProtectionConfiguration.

The attestation signer certificate will automatically be reissued by HGS when it expires, and other HGS nodes will be updated to trust that new certificate. You do not have to worry about managing this certificate.

Lastly, HTTPS certificates must be renewed before they expire. If an HTTPS certificate lapses, Hyper-V hosts communicating to HGS via HTTPS will no longer trust the connection and will be unable to attest or obtain keys for their shielded VMs. You can follow your normal HTTPS certificate renewal process for HGS HTTPS certificates.

 

Q: When I go to retrieve the HGS metadata document, I get an HTTP 500 error saying that the server encountered an internal error. What should I do?

A: In almost every case where HGS cannot serve its metadata document, it is a result of HGS not being able to use one of its certificates. The following conditions must be satisfied for each of the signing, encryption, and communications certificates:

  • Private keys for the certificate are associated with the certificate object in the cert store.
  • The HGS group managed service account has access to use those private keys.
  • The keys use the RSA algorithm and are 2048 bits or longer.
  • The signing certificate allows the Digital Signature key usage
  • The encryption certificate allows the Data Encipherment key usage
  • The communications certificate allows both the Digital Signature and Data Encipherment key usages

If all the above conditions are met, but you are still getting an HTTP 500 error, your certificate may be using a legacy Cryptographic Service Provider or an improperly configured Key Storage Provider (e.g. an HSM KSP that was not given access to use the private keys). Check your certificate template or HSM documentation to identify if your certificate uses a CSP. If it does, reissue the certificate using a KSP so HGS can use it.

The following script can help check these conditions for the signing, encryption and communications certificates.

<#
Instructions: Run the full script below on your HGS server to analyze your certificate configuration.
Output: Summary of all certificates tested. For test-by-test information, inspect the Tests property of the $results object
#>

# Get all KPS certificates
$AllKpsCertificates = Get-HgsKeyProtectionCertificate
$CommunicationsCertificate = Get-HgsKeyProtectionConfiguration
$AllKpsCertificates += [pscustomobject] @{
    Certificate = $CommunicationsCertificate.CommunicationsCertificate
    CertificateData = $CommunicationsCertificate.CommunicationsCertificateData
    CertificateType = "Communications"
}

$results = @()

foreach ($cert in $AllKpsCertificates) {
    $certResult = @{
        Thumbprint = $cert.Certificate.Thumbprint
        CertificateType = $cert.CertificateType
        Tests = @{}
    }
    $errprefix = "TEST FAILURE: The {0} certificate with thumbprint {1}" -f $cert.CertificateType.ToString(), $cert.Certificate.Thumbprint

    # Check basic certificare requirements
    if ($cert.Certificate.GetKeyAlgorithm() -eq '1.2.840.113549.1.1.1') {
        $certResult.Tests.RsaAlgorithm = 'Passed'
    }
    else {
        $certResult.Tests.RsaAlgorithm = 'Failed'
        Write-Warning "$errprefix does use the RSA algorithm."
    }

    if ($cert.Certificate.Version -eq 3) {
        $certResult.Tests.CertificateVersion = 'Passed'
    }
    else {
        $certResult.Tests.CertificateVersion = 'Failed'
        Write-Warning "$errprefix is not a version 3 certificate."
    }

    if ($cert.Certificate.PublicKey.Key.KeySize -ge 2048) {
        $certResult.Tests.KeySize = 'Passed'
    }
    else {
        $certResult.Tests.KeySize = 'Failed'
        Write-Warning "$errprefix has a key length shorter than 2048 bits."
    }

    # Check key usage
    if ($cert.CertificateType -eq 'Encryption' -or $cert.CertificateType -eq 'Communications') {
        if ($cert.Certificate.Extensions['2.5.29.15'].KeyUsages.HasFlag([System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::DataEncipherment)) {
            $certResult.Tests.KeyUsage = 'Passed'
        }
        else {
            $certResult.Tests.KeyUsage = 'Failed'
            Write-Warning "$errprefix does not allow the DataEncipherment key usage."
        }
    }
    else {
        if ($cert.Certificate.Extensions['2.5.29.15'].KeyUsages.HasFlag([System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::DigitalSignature)) {
            $certResult.Tests.KeyUsage = 'Passed'
        }
        else {
            $certResult.Tests.KeyUsage = 'Failed'
            Write-Warning "$errprefix does not allow the DigitalSignature key usage."
        }
    }

    # Check if certificate was added by thumbprint for additional tests
    if ($cert.CertificateData -is [Microsoft.Windows.KpsServer.Common.CertificateManagement.CertificateReference]) {
        if ($cert.Certificate.HasPrivateKey) {
            $certResult.Tests.PrivateKeyPresent = 'Passed'
            

            # Try getting CNG info the "real" way
            if ((Get-TypeData -TypeName System.Security.Cryptography.X509Certificates.X509CertificateExtensionMethods)) {
                if ([System.Security.Cryptography.X509Certificates.X509CertificateExtensionMethods]::HasCngKey($cert.Certificate)) {
                    $providertype = 0

                    $cngKeyInfo = [System.Security.Cryptography.X509Certificates.X509Certificate2ExtensionMethods]::GetCngPrivateKey($cert.Certificate)
                    $provider = $cngKeyInfo.Provider
                    $container = $cngKeyInfo.UniqueName
                }
                else {
                    $providertype = 'CAPI'
                    $provider = $null
                    $container = $null
                }
            }
            else {
                # Try to replicate test using regex parsing
                $certutiloutput = certutil.exe -v -store `"$($cert.CertificateData.StoreName)`" $cert.Thumbprint
                $providertyperegex = [regex]'^ *ProviderType = (.*)$'
                $providerregex = [regex]'^ *Provider = (.*)$'
                $containerregex = [regex]'^ *Unique container name: (.*)$'
                $providertype = $provider = $container = $null
                foreach ($line in $certutiloutput) {
                    if (-not $providertype -and $providertyperegex.IsMatch($line)) {
                        $providertype = $providertyperegex.Match($line).Groups[1].Value
                    }
                    elseif (-not $provider -and $providerregex.IsMatch($line)) {
                        $provider = $providerregex.Match($line).Groups[1].Value
                    }
                    elseif (-not $container -and $containerregex.IsMatch($line)) {
                        $container = $containerregex.Match($line).Groups[1].Value
                    }
                }
            }

            if ($providertype -eq 0) {
                $certResult.Tests.CngKey = 'Passed'

                if ($provider -eq 'Microsoft Software Key Storage Provider') {
                    $keyFilePaths = Join-Path "$env:ALLUSERSPROFILE\Microsoft\Crypto\Keys", "$env:ALLUSERSPROFILE\Microsoft\Crypto\SystemKeys" -ChildPath $container
        
                    if (Test-Path $keyFilePaths[0]) {
                        $keyFile = $keyFilePaths[0]
                    }
                    elseif ((Test-Path $keyFilePaths[1])) {
                        $keyFile = $keyFilePaths[1]
                    }
                    else {
                        $certResult.Tests.PrivateKeyPermissions = 'Failed'
                        Write-Warning "$errprefix has a private key that could not be found. Please verify the HGS gMSA has access to the private key."
                    }
        
                    if ($keyFile) {
                        $keyAcl = Get-Acl $keyFile
                        $gmsaAccount = (Get-IISAppPool -Name KeyProtection).ProcessModel.UserName
                        $accessRule = $keyAcl.Access | Where-Object IdentityReference -eq $gmsaAccount
                        if ($accessRule -and $accessRule.AccessControlType -eq 'Allow' -and $accessRule.FileSystemRights.HasFlag([System.Security.AccessControl.FileSystemRights]::Read)) {
                            $certResult.Tests.PrivateKeyPermissions = 'Passed'
                        }
                        else {
                            $certResult.Tests.PrivateKeyPermissions = 'Failed'
                            Write-Warning "$errprefix is not configured to allow the HGS gMSA account access to the private key."
                        }
                    }
                }
                else {
                    $certResult.Tests.PrivateKeyPermissions = 'Skipped'
                    Write-Warning ("TEST SKIPPED: The {0} certificate with thumbprint {1} uses a custom key storage provider. This script cannot check if the HGS gMSA has access to the private key." -f $cert.CertificateType, $cert.Certificate.Thumbprint)
                }
            }
            else {
                $certResult.Tests.CngKey = 'Failed'
                $certResult.Tests.PrivateKeyPermissions = 'Skipped'
                Write-Warning "$errprefix is using a legacy crypto service provider to access its private key instead of a key storage provider."
            }
        }
        else {
            $certResult.Tests.PrivateKeyPresent = 'Failed'
            $certResult.Tests.PrivateKeyPermissions = 'Skipped'
            $certResult.Tests.CngKey = 'Skipped'
            Write-Warning "$errprefix does not have a private key associated with it."
        }

        
    }
    else {
        # The certificate was added by PFX
        $certResult.Tests.PrivateKeyPresent = 'Passed'
        $certResult.Tests.PrivateKeyPermissions = 'Passed'
        $certResult.Tests.CngKey = 'Passed'
    }

    # Compute final result
    if ($certResult.Tests.Values -contains 'Failed') {
        $certResult.Result = 'Failed'
    }
    elseif ($certResult.Tests.Values -contains 'Skipped') {
        $certResult.Result = 'Passed (some tests skipped)'
    }
    else {
        $certResult.Result = 'Passed'
    }

    $results += [pscustomobject] $certResult
}

Format-Table -InputObject $results -AutoSize -Property 'Thumbprint', 'CertificateType', 'Result'

These were the most common questions we've received on certificates, but if you've run into an issue not described above, let us know in the comments or send us an email at shieldedvmfeedback@microsoft.com.


Comments (0)

Skip to main content