Windows App service, intermediate certificates and Cross signing

Stefan Hanrath - AcceptEasy 26 Reputation points
2025-06-24T12:28:41.17+00:00

Hi! I've run into an interesting problem serving up traffic to older clients: IIS seems to only give back the leaf and intermediate CA, which itself has a root certificate as issuer.

This behaviour however does not seem to match more recent practices and developments:

  • current wider proliferation of both intermediate CA's
  • cross-signing of root certificates for backwards compatibility

So: in the old days, we used to do this, for which IIS returning only the leaf and leaf-1 depth cert was fine:

app service returns [
mySite.com (issued by i.e. 'Sectigo RSA Domain Validation Secure Server CA')
+- Sectigo RSA Domain Validation Secure Server CA (issued by 'USERTrust RSA Certification Authority')
]
client matches issuer
+- USERTrust RSA Certification Authority (in root store, chain is verified and trusted)

A little bit later, because revoking long lived root certs is problematic, CAs introduce intermediate CAs:

app service returns [
mySite.com (issued by i.e. 'Sectigo Public Server Authentication CA DV R36')
+- Sectigo Public Server Authentication CA DV R36 (issued by 'Sectigo Public Server Authentication Root R46')
]
client matches issuer
+- Sectigo Public Server Authentication Root R46 (in root store, chain is verified and trusted)

(still fine for most modern up to date clients with recently updated root CA store)

For backwards compatibility with older clients, the CAs provide root certificates that are cross-signed with older, more widespread root certificates (see https://www.sectigo.com/sectigo-public-root-cas-migration).
This scenario, combined with the additional depth introduced by intermediate CAs causes things currently to break with a non-insignificant fraction of mostly older mac/iOS devices, when serving only the first 2 certs up with App service:

app service returns [
mySite.com (issued by i.e. 'Sectigo Public Server Authentication CA DV R36')
+- Sectigo Public Server Authentication CA DV R36 (issued by 'Sectigo Public Server Authentication Root R46')
]
client does not find
+- Sectigo Public Server Authentication Root R46 (issued by 'USERTrust RSA Certification Authority')
+- USERTrust RSA Certification Authority (in root store, chain is verified and trusted)
despite the USERTrust cross signing (which is present in root CA store)

What it does instead is stop at root r46 being an untrusted certificate, and i get the 'this site is unsafe' invalid TLS cert notifications warnings on the client side.

In a windows app service, i see it only consistently tries to serve up the leaf
certificate (for my org level domain) and the intermediate CA.
This behaviour seems to be rather specific to IIS / app service in particular.

This does not seem to change if i:
re-upload the full public certificate chain to the USERTrust root attached to the key into key vault as pfx
re-upload the full public certificate chain to the USERTrust root attached to the key into key vault as pfx into app service certificate store (the one attached to web spaces)

What is the guidance to have a (windows) app service respond with more of the certificate chain? As it seems to stop short for the legacy clients.
Specifically, how do i control whether app service serves up the specifically cross signed root in the chain? i.e. https://crt.sh/?id=11405654893
An example of a server succesfully doing this: https://sectigopublicserverauthenticationrootr46-ev.sectigo.com

Azure App Service
Azure App Service
Azure App Service is a service used to create and deploy scalable, mission-critical web apps.
8,930 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Prabhavathi Manchala 2,315 Reputation points Microsoft External Staff Moderator
    2025-06-24T14:29:11.0433333+00:00

    Hi Stefan Hanrath - AcceptEasy,

    By default, IIS (which underlies Windows App Services) only sends the leaf certificate and its immediate issuer (the intermediate certificate) during the TLS handshake. It does not automatically include the full chain, especially if there's a cross-signed root needed by older clients to establish trust.

    In your case:

    • Your certificate chain involves a modern root (R46) that's not trusted by older clients.
    • A cross-signed version of that root exists (signed by an older root like USERTrust RSA Certification Authority) to support backward compatibility.
    • But since IIS isn't sending this cross-signed root, older clients (with outdated root stores) can’t validate the chain => resulting in TLS errors or unsafe site warnings.

    You correctly uploaded the full certificate chain (including the root) in the .pfx file to Key Vault or the App Service Certificate store, but App Service still only serves the leaf and intermediate certificates. This is expected behavior, as IIS does not include the root certificate in the TLS handshake, even if it's present in the .pfx.

    To ensure older clients also work, you need to manually serve the full certificate chain, including the cross-signed root, by using TLS certificate bundling.

    1. Host Full Certificate Chain via Azure Front Door or Application Gateway

    Windows App Service has limited control over full chain delivery. Instead, use Azure Front Door or Application Gateway in front of the App Service and configure them with the full certificate chain, including the cross-signed root. These services give you full TLS chain control, support older clients, and also add benefits like global CDN and web application firewall (WAF).

    • Upload the full certificate chain (.pfx including cross-signed root) to Azure Key Vault.
    • Link it to Azure Front Door or Application Gateway Listener using HTTPS configuration.
    • Validate the full chain with SSL Labs

    Use Azure Front Door with Key Vault

    Configure SSL on Azure Application Gateway

    1. Use Linux App Service (Instead of Windows) for Full TLS Chain Control

    Unlike Windows App Service, Linux-based App Services give you more flexibility. When you bring your own certificate using a custom container or custom domain binding, it can serve the full chain.

    • Switch to Linux App Service Plan (if feasible).
    • Bind your full .pfx that includes leaf + intermediate + cross-signed root certs.
    • Validate the chain again with tools like SSL Labs

    Secure a custom domain with SSL in Linux App Service

    If you must stay on Windows App Service, consider placing it behind Azure Front Door where you have full control of the TLS certificate chain. This is the most future-proof and compatible solution across all clients, especially legacy platforms.

    If the answer is helpful, please click Accept Answer and kindly upvote it so that other people who faces similar issue may get benefitted from it.

    Let me know if you have any further Queries.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.