Skip to content

Using Alternate Trust Chains

The ACME protocol allows for a CA to offer alternate trust chains in order to accommodate the natural lifecycle of Root and Issuing certificates. As of this writing, the only public ACME CA that currently offers alternate trust chains is Let's Encrypt. But the instructions in this guide should work for any ACME CA.

Let's Encrypt Options

To understand why Let's Encrypt is offering multiple trust chains and why you as a site/service operator would choose one or the other, it is helpful to read the following posts:

Your default choice is currently the longer chain that builds to the expired DST Root CA X3 self-signed certificate which should be compatible with almost all Android devices until 2024. The alternate choice is the shorter chain that builds to the ISRG Root X1 self-signed certificate which doesn't expire until 2035.

Ultimately, your choice should depend on the clients that are connecting to your service. But if you don't know, it's probably safest to just leave the default. Let's Encrypt also has a Certificate Compatibility page that can help.

It is also a perfectly valid option to switch to a different public ACME CA either permanently or until the dust settles on the DST Root expiration.

Picking an Alternate Chain

New-PACertificate, New-PAOrder, and Set-PAOrder all have a -PreferredChain parameter that work the same way. You provide the common name of a certificate in the chain you want to select. For Let's Encrypt, that would be ISRG Root X1 even though it exists in both chains. The alternate chain wins because that cert is closer to the root (it is the root) than the default chain.

Here's an example of getting a new cert with the alternate chain using splatting.

$certParams = @{
    Domain = '*.example.com','example.com'
    AcceptTOS = $true
    Contact = 'admin@example.com'
    Plugin = 'FakeDNS'
    PluginArgs = @{
        FDToken = (Read-Host 'FakeDNS API Token' -AsSecureString)
    }
    PreferredChain = 'ISRG Root X1'
}
New-PACertificate @certParams

You can also modify an existing order to use the alternate chain which will change both the current certificate files (if they exist) and future renewals.

Set-PAOrder -Name 'example.com' -PreferredChain 'ISRG Root X1'

Warning

Changing the chain on an existing certificate will only update the files in the Posh-ACME order folder. Even if the order has the Install property set to $true, it will not re-import the current certificate to the Windows certificate store. It will only do that on the next renewal.

Serving the Alternate Chain from Windows

While the -PreferredChain option will make Posh-ACME download the alternate chain for the files in your config, you may notice that on Windows your website/application is still serving the default chain. Unlike many Linux applications that have explicit configuration options for chain configuration, applications that use the Windows certificate store usually rely on the underlying operating system to decide what chain to serve with the leaf certificate.

There does not seem to be a way to differentiate the chains being served based on application. All websites and applications using leaf certs from the same Intermediate CA will serve the same chain. But it is possible to influence which chain based on the by manipulating the contents of the various Windows trust stores.

The default chain that Windows picks for an LE cert following the expiration of DST Root CA X3 is actually Let's Encrypt's shorter "alternate" chain which does not include the cross-signed copy of ISRG Root X1 needed for old Android compatibility. Convincing Windows to serve Let's Encrypt's longer "default" chain that does support old Android devices currently requires a hack that involves un-trusting the legitimate self-signed ISRG Root X1 on the user account hosting your service. In the case of IIS, that usually means the local SYSTEM account.

There are a number of different ways to make the modifications, but generally speaking the following needs to happen in the cert stores associated with the user running the service.

Warning

This process is an unsupported hack and will partially break certificate validation against sites/services using Let's Encrypt certificates when accessed by software or web browsers on this user account. It should not affect validation for other users on the system.

Option 1: Manually using PsExec

  • Download the 3 certificates linked above (2 versions of ISRG Root X1 and a copy of R3)
  • Download Microsoft's PsExec utility and run the following from an admin prompt to open the Certificate Manager for the SYSTEM user.
psexec.exe -i -s certmgr.msc
  • Navigate to Untrusted Certificates and expand
  • Right click it, select All Tasks - Import
  • Browse to the self-signed ISRG Root X1 you downloaded and complete the wizard to import it
  • Navigate to Intermediate Certification Authorities and expand
  • Right click it, select All Tasks - Import
  • Browse to the cross-signed ISRG Root X1 you downloaded and complete the wizard to import it
  • Look for an existing copy of R3 issued by ISRG Root X1 and expiring in 2025. (It's okay if there are multiple copies listed)
  • If it doesn't exist, import it the same way you did for the cross-signed ISRG Root X1

Option 2: Import via Registry File

Many find it easier to import a registry file containing the necessary cert changes. Here are two that allow you to switch back and forth between the "default" and "alternate" chain configurations.

The first one imports the 3 certs as described in the manual method. The second one deletes them. Download the one you want, remove the .txt extension so it becomes .reg, and double-click to import it.

Trigger Cert Chain Rebuild

In order for the cert changes to take effect, the most reliable method is to reboot the server. If you are unable or don't want to reboot, you may also be able to trigger a chain rebuild by causing IIS to rebind the certificate on your site.

On Windows Server 2012 R2 or newer, you can use the following command to rebind the cert as long as you know the certificate thumbprint. From PowerShell:

& $env:SystemRoot\system32\inetsrv\appcmd.exe renew binding /oldcert:THUMBPRINT /newcert:THUMBPRINT

On earlier OSes, you can try modifying the binding from IIS Manager or just delete and re-create it. But again, the most reliable way is a reboot.

Verify the Chain Being Served

If your website is exposed to the Internet, you can use a number of web based SSL checkers to verify which chain is being served by your site. Here are a couple popular ones:

If your website or service is only listening on your internal network, the most common way to check the chain is using OpenSSL. It's usually pre-installed on Linux and MacOS. But you'll have to download and install it for Windows. A popular distribution is available from Shining Light Productions. All you should need is the "Light" Win64 version of whatever is the latest build.

Run the following to check your site where SERVER is the hostname or IP of your server.

openssl s_client -connect SERVER:443

If your server requires using an SNI hostname, you can use this alternative:

openssl s_client -connect SERVER:443 -servername HOSTNAME

The output will be quite long and you may need to Ctrl-C to cancel the command. But the output you're looking for should be within the first 10 lines of output. There will be a block of text between two sets of --- characters that should look like either of these:

Default/Long Chain:

---
Certificate chain
 0 s:CN = example.com
   i:C = US, O = Let's Encrypt, CN = R3
 1 s:C = US, O = Let's Encrypt, CN = R3
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
 2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
   i:O = Digital Signature Trust Co., CN = DST Root CA X3
---

Alternate/Short Chain:

---
Certificate chain
 0 s:CN = example.com
   i:C = US, O = Let's Encrypt, CN = R3
 1 s:C = US, O = Let's Encrypt, CN = R3
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
---