· ~4 min read

Building a PKI with mutual TLS, and what a MitM does without it

A two-tier certificate authority, an Apache server on elliptic-curve keys that only accepts clients with a certificate, and a man-in-the-middle simulation on an unprotected LAN that shows why these controls exist.

Goal

Build the certificate infrastructure a small organisation would need, lock a web service behind mutual TLS, and then look at the same kind of network from the attacker's side, to see what goes wrong when layer 2 and TLS are not protected. The defensive part is the core of this lab; the attack is there to justify it.

The commands and screenshots are in the repository on GitHub.

A two-tier certificate authority

TierRoleWhere it lives
Root CA (RSA 4096, key encrypted with AES-256)Signs only the intermediateOffline
Intermediate CA (RSA 4096)Signs servers and clients day to dayOnline, replaceable
Server (ECDSA P-256)The Apache web serverWeb server
Client (RSA 4096, exported as .p12)A user's browserUser's machine

The point of the second tier is damage control. If the intermediate key is compromised, the root revokes it and issues a new one; nothing that trusts the root has to change. If the root itself were online and stolen, the whole hierarchy would have to be rebuilt.

The server uses an elliptic-curve key (P-256): the same security level as a much longer RSA key, with smaller handshakes and less CPU per connection.

Mutual TLS on Apache

Ordinary TLS proves the server to the client. Mutual TLS also makes the client prove itself, with a certificate from a CA the server trusts:

SSLCertificateFile      server.crt
SSLCertificateKeyFile   server.key
SSLCertificateChainFile chain.crt

SSLCACertificateFile    chain.crt
SSLVerifyClient require
SSLVerifyDepth  2

SSLVerifyClient require refuses the TLS handshake to anyone without a valid client certificate; there is no login page to attack because the connection never gets that far. SSLVerifyDepth 2 allows exactly the chain client, intermediate, root. The configuration was then checked with sslscan.

The other side: a man-in-the-middle on an unprotected LAN

In a separate simulation, on an isolated lab network, I played the attacker against a victim machine on the same LAN. ARP poisoning put the attacker between the victim and the gateway, and a cloned login page on a plain HTTP address collected the credentials the victim typed. Nothing about it was sophisticated, and that is the lesson: on a flat LAN with no layer-2 protection, a user who does not check the address bar is one step from handing over a password.

The same attack does nothing against the mTLS service above: the attacker cannot present the server's certificate, and cannot complete the handshake without a client certificate either.

Mitigations

What I learned

Re-reading my own write-up, I would correct and add a few things.

A personal lab on an isolated virtual network; the attack ran only against my own lab machines.

Want the configs or code from this lab, or have a question? Email me at papas@viotnet.com

← all posts