What is TLS?
Before reaching our goal of understanding mTLS, we need to understand regular TLS. There are tons of resources out there that vary in technical depth. My goal here is familiarization, not mastery (which requires complex understanding of cryptography and various standards like X.509. If you are aiming for mastery, I suggest looking into a course or a fine book. If you are hoping to become familiar with the basic ideas and terminology, look no further!
You have already used TLS hundreds of times today. Any websites you visit with
https as the protocol, is making use of TLS. The server has used asymmetric encryption to encrypt your requests (providing confidentiality) and has also proven its identity to you, so that you can be confident that it was actually Google who answered your request on https://www.google.com, and not your malicious neighbor who likes to hack you.
Before we proceed further, let’s briefly talk about SSL and how it relates to TLS (the two are often confused). SSL was the predecessor of TLS and is deprecated. However, you will sometimes see SSL and TLS used interchangeably where technical precision is paramount, or to support legacy implementations (for example Nginx variables often include “ssl” in their name, even though it’s actually TLS being worked on).
As you gain experience, you’ll generally be able to know whether the speaker means SSL or TLS, but until then it’s pretty safe to assume a person means TLS even if they say SSL. If you are discussing older, insecure, unsupported versions, that could be a reference to actual SSL. Generally speaking though, it is likely that TLS is what is meant.
How does TLS verify identities?
Since we are primarily interested in the identity verification portion of TLS for this blog post, let’s talk about how TLS currently verifies identity.
When setting up a web service that uses TLS, you need to generate a public/private key pair. The terms often used are “key”, rather than private key, and “certificate”, rather than public key. If you previously read the Asymmetric Encryption post, don’t let these terms throw you off! The concept is essentially the same, with some minor additions.
The “key” is the private key, and the “certificate” contains the public key that you will share with the world. When the client connects to the server, the client will ask the server to identify itself. The server then presents its certificate to the client. The client issues the server a challenge by encrypting a secret number using the public key in the certificate, and asking the server to decrypt it. Only someone with access to the corresponding private key will be able to decrypt the number successfully. This in effect proves that the server has the private key (which means the server is the owner of this certificate. You never shared your private key, right?). This is the basic building block of how TLS performs identity verification!
But wait! There’s something missing here…
How can you trust that the server isn’t lying about their identity?! For example, what stops Eve from generating a private/public keypair and claiming to be Bob on her certificate? Even though Eve has the corresponding private key to the certificate, that doesn’t assure us that the certificate isn’t lying. So far in our toolkit, there is nothing to prevent Eve from populating that certificate with lies about her identity!
This is where trust chains (also called chains of trust) come in. Trust chains link trusted certificates together, lending credibility of known/trusted certificates to unknown certificates that have been vouched for.
This is often the most confusing aspect, so try to bear with me. If you need to read these sections a few times, don’t despair. You are in good company. Albert Einstein had to read this blog post several times before it finally clicked, and he discovered general relativity! So don’t feel bad.
How can Alice Trust that Bob is Bob?
Let’s start with a simple analogy. You have a best friend, named Ben. It’s me actually, I’m your best friend. When you come to my house there is a person you have never met before. He introduces himself as “Kevin.” But you have never met him before, so he could be lying about his name! However, you turn to me and say, “Ben is this Kevin?” I assure you that his name is Kevin, and you are satisfied. You now trust that Kevin really is Kevin because I said he is, and you trust me.
Let’s get back to the server now. In order to know if Alice can trust Bob, she needs to find a trusted third party to vouch for Bob’s identity (someone who both Alice and Bob mutually trust). If my friend Steve is trusted by Alice and Bob, and he tells Alice that Bob’s certificate is valid, then she knows that she can trust Bob’s certificate. Steve is trustworthy, and Steve has vouched for Bob. In this scenario, Steve is acting as a Certificate Authority. He has cryptographically “signed” Bob’s certificate, so you can be sure it is legitimate.
A Certificate Authority is a trusted third party that can “sign” certificates adding their stamp of approval. This allows the verifier to know that they mutually trust somebody. A signature is done by using the trusted third party’s private key to encrypt a known value, which is then added to the certificate. A verifier can then use the signer’s public certificate to decrypt that known value, and verify that it matches the expectation. Only a person in possession of the third party’s private key could have encrypted the value such that it decrypts correct, so this proves that (as long as the private key has not been compromised) the trusted third party (the Certificate Authority) trusts this certificate’s claims. If you trust the Certificate Authority, then you can trust this certificate.
There are often several layers of certificate authorities or links in the trust chain, for various reasons. Let’s go back to our scenario. Steve has generated public/private key pairs for himself so that he can sign certificates for people. He is hoping to turn this into a successful business, but that means that lots of people will need to trust him. If lots of people already trust his signature, then his private key becomes extremely valuable. If Eve is able to steal Steve’s private key, she can create her own bogus certificates with any name she likes and sign them as Steve! This would obviously compromise security for lots of sites, and also destroy Steve’s reputation in a way he would likely never recover from.
Because of this risk, Steve decided to keep his private key extra secure by locking it in his safe. However, as he scales his business and gains more and more customers, it is getting painful to open the safe and pull out the private key every time he needs to sign a certificate. In architecture we would say his process doesn’t scale.
Not one to be outdone by a scaling challenge, Steve creates a few additional certificate authorities (CAs), and signs those certificates with his original private key. The original is now called the “root” CA while the others are now called “intermediate CAs.”
Now Steve can distribute his root public key (his public certificate) widely, but he can do the signing using a less juicy intermediate CA private key. These are still very sensitive so Steve works hard to keep them safe, but in the event that they are compromised somehow, they can be revoked and recreated without requiring him to redistribute his new public key to everyone, which would be extremely difficult to do (because in real life it is baked into most operating systems and browsers, so is nearly impossible to change in a timely manner).
In real life, Steve would be a company that is a trusted root CA, such as GlobalSign or DigiCert, etc.
If you want, you can see exactly how these public keys/certificates get bundled into your operating system or browser. The steps vary greatly by OS/browser. If you are using Android, look at the source files. Try clicking on a certificate and reviewing the information that is in there. If you are a Windows user, you may be interested in reviewing Microsoft’s trust root. Most Linux distributions have the trusted CAs packaged in their repositories. A Google search can turn them up.
When a client connects to a server using TLS, the server will send it’s certificate to the client, and the client can then walk the trust chain (follow each certificate signer) until arriving at one that is already trusted by the operating system or browser. If this happens, and the server’s hostname matches the one the client intended to reach, identity is proven and the connection is successful. The browser will now show the lock icon in the toolbar.
Now you know TLS! See, it wasn’t that bad! Just one more small concept and you’ve got mTLS down!
What is the “m” in “mTLS?”
In the previous scenario, notice that while Alice was able to verify the identity of Bob, Bob was not able to verify her identity. Most of the time the server doesn’t care to verify the identity of the client, because they are public internet-facing servers anyway.
Sometimes however, especially in enterprise environments, we don’t want just anybody to call our service, even if they are on the same network already. If we are writing a backend service that is part of a Service Oriented Architecture (SoA) for example, it may only be valid for one particular service to call us, and nobody else, especially not end users. In this case, we may want to verify the client’s identity before allowing them to make HTTP requests to us. If the client’s identity is not on our authorization list, we want to deny them access.
This brings us to the “m” in “mTLS.” The “m” stands for “mutual,” which means the client and server each verify each other’s identities before proceeding on to the HTTP exchange. There are no limitations here other than that the client must have (and submit) a certificate signed by a CA that the server recognizes. In enterprise environments, this is often a company-run internal CA, but it does not have to be.
Perhaps I can share an example from my real life where I used mTLS. I created an instance of Password Maker for myself, but I changed several of the defaults to make using it easier and gave me less to remember. Unfortunately for security, this convenience for me would also make it easier for an attacker to guess my passwords. It’s the equivalent of putting a “password hint” up. It’s awesome for UX, but bad for security.
Since I was the the only valid user in the world for this server, I wanted a way to expose it to the internet at large (so I could access it from anywhere I happened to be) but still restrict it to only myself. Unfortunately the site was a simple HTML page with no backend in which to do access control. However, this is not a problem because I have mTLS!
I generated my own root CA, and minted a client cert and a server cert, and configured my nginx web server (serving the HTML page from my Digital Ocean droplet) to require client authentication prior to serving the page. I then put my client key/cert on my laptop and android phone, and Bob was my uncle. I had a secure setup, such that nobody except me could access my Password Maker HTML page. Perfect!
What happens when my wife needs access too? Not a problem! I could mint her a client certificate signed with my root CA, and with no changes at all required on the server (because it already trusts my root CA) my wife now has access. This setup scales very well.
Now that you know about mTLS, the next step is to add it to a service of yours! Stay tuned for a future post walking through adding mTLS to a few different services. Follow me to receive updates when I post.