What else can you stuff in a certificate chain?

Profile image of Mattias Geniar

Mattias Geniar, May 25, 2020

Follow me on Twitter as @mattiasgeniar

I recently learned that quite a few (old) root certificates are going to expire, and many websites still send those along in the TLS handshake.

Browsers don’t really seem to care about expired, irrelevant, certificates in a chain - so what else could you chuck in a certificate chain? Let’s find out! 😎

A quick recap on certificate chains

The tl;dr version of certificates: your computer/server comes with a set of root certificates that it trusts, and every certificate will be validated against one of those root certificates.

Usually, there’s a certificate in between, called an intermediate that chains the SSL certificate of a website, through that intermediary certificate, to the root certificate.

Certificate chain for ma.ttias.be

For Let’s Encrypt issued certificates, they are validated against the Let’s Encrypt Authority X3 one, and that is validated against a pre-installed certificate DST Root CA X3.

We’ve now established that certificates form a chain, and it’s important there’s a validation path between domain ↔️ intermediate ↔️ root. Got it.

The test environment

The testing below was done on this website: tls-long-certificate-chain.immutable.be.

In Firefox, you’ll just be able to click through the security warning.

In Chrome, because this is a self-signed certificate, you need to type “thisisunsafe” anywhere on the page to acknowledge you want to continue.

What if you include additional, irrelevant, certificates?

So some websites send along a very old root certificate to their clients. What if instead of just one root certificate, we include - say - 82 root certificates in the chain? 😈

To test this, I modified my Caddy server and instead of using its internal Let’s Encrypt mechanisme, I supplied it my own (self-signed) certificate.

$ cat Caddyfile

https://tls-long-certificate-chain.immutable.be {

    tls certificate.crt certificate.key


The certificate.crt file contains, besides my self-signed certificate, a random selection of 82 other root certificates that are in no way related to this certificate.

$ grep -c 'BEGIN CERT' certificate.crt-long

(The original certificate is in there too, so it’s 1 + 82 random certificates.)

The certificate.crt now weights 132KB in size as opposed to the lean 1.9KB it was before.

And when I reload the webserver … it still just works!

Certificate chain for ma.ttias.be

Are we even sending the entire chain?

To verify, let’s fall back to using openssl to see which certificates we’re actually sending.

$ openssl \
    s_client \
    -showcerts \
    -connect tls-long-certificate-chain.immutable.be:443 \
    -servername tls-long-certificate-chain.immutable.be

depth=0 CN = tls-long-certificate-chain.immutable.be
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = tls-long-certificate-chain.immutable.be
verify return:1
Certificate chain

 0 s:/CN=tls-long-certificate-chain.immutable.be

 1 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

<< a bunch of other certs here >>

81 s:/C=DE/O=T-Systems Enterprise Services GmbH/OU=T-Systems Trust Center/CN=T-TeleSec GlobalRoot Class 2
   i:/C=DE/O=T-Systems Enterprise Services GmbH/OU=T-Systems Trust Center/CN=T-TeleSec GlobalRoot Class 2

82 s:/CN=Atos TrustedRoot 2011/O=Atos/C=DE
   i:/CN=Atos TrustedRoot 2011/O=Atos/C=DE

Yup, they’re in there, all 83 of them!

Why the limit at ~80 root certificates?

Well it’s not really the 82 that is the limit. OpenSSL has a limit of how large message exchanges can get. If you try to use openssl to fetch the info from a site with too many certificates in its chain, you get this error:

$ openssl \
    s_client \
    -showcerts \
    -connect tls-long-certificate-chain.immutable.be:443 \
    -servername tls-long-certificate-chain.immutable.be

4506226284:error:14006098:SSL routines:CONNECT_CR_CERT:excessive
message size:/AppleInternal/BuildRoot/Library/Caches/com.apple.xbs

With curl (and I’m guessing anything that builds on top of libcurl), you would get this error:

error:1408E098:SSL routines:ssl3_get_message:excessive message size

So there’s some good protection against client-side overflows there. I was hoping to be able to cause some kind of DoS on the client-side, but that doesn’t seem to be the case.

When I tested this, I found the limit to be around 80 certificates in a chain, but it’ll depend on the data already encoded in the certificate.

Network inspectors & TLS traffic

This experiment lead to an observation: both Chrome and Firefox’s network inspector do not show the network traffic generated by the certificate exchange.

If a browser sends 1 certificate or 83, the total network size remains the same in the inspector. It’s impossible to see how much data traffic was generated by the SSL/TLS handshakes at this moment.

What’s the performance impact?

To be fair, it’s quite small. I would have expected a substantial increase of the time spent in TLS-negotations, but that’s not really the case.

I added those 82 root certificates to the config around 2PM, you can see a noticeable increase in this graph, but it’s nowhere near alarming.

Certificate chain for ma.ttias.be

(Graph provided by the beta version of the Oh Dear monitor.)

In short: if you currently have 3 certificates in your chain, you won’t be saving much by trying to make the chain shorter.

What can you do with this?

Now we’ve confirmed that you can chuck in any data in that certificate chain, as long as it’s properly encoded, what could you do with this?

Some things come to mind.

Capture the Flag challenge

A level in a capture the flag security game: find a passphrase hidden in a certificate in the chain.

Since the extra certificates aren’t shown in the browser when you inspect the certificate, you would need to extract them using openssl's CLI tools.

That’s some next level digging right there!

Data extraction

You could use this to perform data extraction from secure locations. There are already many ways of using DNS queries to extract data from secure environments, HTTPS might be an alternative solution where an attacker could extract data by encoding it in a certificate chain.

If you can expose an HTTPS service to the outside world and have control over the certificate configurations, I’m pretty sure you could do this completely undetected (as far as network traffic inspection goes).

But if you already have the ability to expose ports and manage certificates on your infiltraded environment, I’m guessing this approach will be overkill. 😅

Denial-of-Service possibility?

Modern browsers really don’t make a fuzz of seeing a lot of certificates in the chain.

But how do older devices react? Old version of java? Embedded devices? Ancient firmwares?

There might still be an opportunity there for denial of services, if you can trick them into connecting to your endpoints.

Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.