Taking a quick look again at setting up client authentication in Apache 2 – my previous post on the topic was fine, right up until an OpenSSL vuln was discovered where renegotiation handshakes were not properly associated with existing connections – thus potentially allowing for a Man-in-the-Middle attack. Loads of additional reading on the CVE advisory if you really want to know more.
OpenSSL 0.9.8m was released to fix the bug – the fix was to switch to a newer and more poorly supported method of allowing renegotiations. Practical outcome: client auth in many web apps using Apache and mod_ssl simply stopped working. I found out the hard way when a service I had set up to use client auth to keep non-work-people out broke after OpenSSL was updated on that box. Helpfully, Apple still haven’t seen fit to update the version of Apache in OS X Server, so client auth is still down for the count on Apple servers (add that to the laundry list of reasons I dislike Apple server OS’en..)
At any rate – the above is all ancient history. After Googling for an answer, giving up for a while and finally getting a tip-off in a comment on this blog, it would seem that you can switch the old method of SSL renegotiation back on with an Apache directive. Here’s how:
WARNING: this workaround is definitely not recommended if it can be avoided, because you’re intentionally switching a known security vulnerability back on. The “proper” fix is to set your website up such that renegotiation isn’t required – i.e., placing all the content that needs to be locked down with client auth in its’ own subdomain / VirtualHost.
Right, now my ass is covered – you need to start out with the following:
- Apache 2.2.15 or newer
- OpenSSL (mod_ssl) 0.9.8m or newer
If you haven’t got the above two items, you need to fix that first.
I’m going to assume that you’ve already got SSL set up and working – there are at least 9000 howto’s on the Internets, so little point in me covering that. Once your SSL is working without error, you’ll need to add this to your VirtualHost configuration:
SSLEngine On
SSLCertificateFile /path/to/ssl.crt
SSLCertificateKeyFile /path/to/private.key
SSLCADNRequestFile /path/to/client-cert-issuing-ca.crt
SSLInsecureRenegotiation on
The first three lines you should already have, and possibly also a SSLCertificateChainFile entry if you have a chained SSL cert.
The fourth line tells the client what CAs the server will accept a certificate for, and thus should point to a file containing the Issuing CA (in PEM format) for your client certs. This command is particularly important if you use an Intermediate CA to issue certificates (rather than just the Root CA). It’s optional — and doesn’t get used to validate client certs — but it’s respected by at least Internet Explorer, so not a bad idea to include it.
The fifth line does exactly what it says; it’s what actually fixes things here. Do note that both the fourth and fifth lines are only valid within a Server or Virtual Host context; you can’t use them in a Directory or Location section.
You will then need the following at the Directory level:
SSLRequireSSL
SSLVerifyClient require
SSLCACertificateFile /path/to/file-with-full-ca-path.crt
SSLVerifyDepth x
<FilesMatch “.(cgi|pl)$”>
SSLOptions +StdEnvVars
</FilesMatch>
Obviously this is in addition to whatever else you have configured for the Directory section. First line requires SSL on the server, second line requires a certificate from the client.
The third line tells the server what CAs to trust for client auth; if you have a chained hierarchy for issuing client certificates, this file should contain all of the Intermediate CAs up to and including the Root CA (concatenated together in PEM format). Including the full chain is new to me; I don’t know what version of Apache started requiring this, but you’ll get non-obvious errors in your log files if you don’t have all of the CAs required here.
Fourth line tells the server how far down it can traverse a chain to verify a certificate before giving up – 1 if the certificate is directly signed by a Root CA, 2 if there’s one Intermediate CA and so on.
The FilesMatch section and SSLOptions statement aren’t absolutely required, but if you want to log any of the information from the client cert or make said information available in the environment variables — you’ll need it. Grabbing all this information comes at a performance penalty, so it makes good sense to restrict what types of files the server extracts it for.
Another item worth researching and including in your config is the SSLRequire directive – it’s reasonably complicated, but allows you to control what client certs are allowed based on things like Subject DN and Issuer DN. Which leads me to my last recommendation..:
Make a point of reading the mod_ssl documentation. You’ll be glad you did!
- zac.