Installing your own CA authority to force client authentication
I ran into a lot of caveats doing this for the first time, so I thought I might record this for posterity. First, we have two servers. In this case, the whole point of this is an added layer o f security for our server, we'll call it goliath. It has a web service running via apache, and we only want server david to access that service. We can do it with IP filtering, of course, but we think down the road we may want to allow a different server access, and we want to add an additional layer of security even if someone somehow defeats an filtering in place.
A more likely reason to do this might be that you want to authenticate a browser. We're not going to go into that, because I did not need to install the client cert on the browser, but a lot o f this will still be applicable.
- Apache 2 with mod_ssl
- client host has openssl as well, and our goal is to get wget working
Step 1: Create a CA
You can edit your openssl.cnf if you like. Alternately, you can plan to specify the -config flag with a lot of your openssl commands. In my case, I'm using what I think was the default, which con tains this line:
So I did:######################################################## [ CA_default ] dir = ./demoCA # Where everything is kept
This should create a directory matching you "dir" setting, like demoCA. Contents:# mkdir -p /etc/ssl/goliath # cd /etc/ssl/goliatch # /usr/share/ssl/misc/CA -newca
Roughly. That's my contents after signing a few certs. Over to the david box, we need to generate a key and a csr:cacert.pem crl index.txt.old private serial.old certs index.txt newcerts serial
It's unimportant at the moment where you're issuing those so long as you remember. Now, you copy the csr over to goliatch. For example:# openssl genrsa -out david.key 1024 # chmod 400 david.key # openssl req -new -key david.key -out david.csr
Back on david, we now need to sign the csr with our CA key. This is where things are totally different from the self-signing routine many have probably done with an ssl cert in the past. On goliath:# scp david.scp root@goliath:/var/tmp
Caveat: I put in -startdate here. Why? When I did this, I was testing immediately, but I had one server on GMT and the other on Mountain time. Before I did this, the MST server actually th ought the "valid from:" date was in the future. So when I did it over, I made sure to specify a startdate one day in the past. The actual formula for the UTC date code would be, for example, for Jun 14th 2005 at noon: 050614120000Z Back on david, we retrieve the cert:# cd /etc/ssl/goliath # openssl ca -startdate YYMMDDHHMMSSZ -policy policy_anything \ -out /var/tmp/david.crt -infiles /var/tmp/david.csr
Ok. Now, we need to configure our server. Wherever applicable (in my case, it was in conf.d/ssl.conf and in conf.d/goliath.domain.com.conf), we need to set up these lines:# scp root@goliath:/var/tmp/david.crt .
Those all don't necessarily need to go together, but do put the SSLVerify lines directly under SSLEngine On. Now, issue an "apachectl graceful" to get that config going. At this point, back on david, you should be able to do the following:SSLEngine On SSLVerifyClient require SSLVerifyDepth 5 SSLCACertificateFile /etc/ssl/goliath/demoCA/cacert.pem
Please note this assumes that GOLIATH already has a valid ssl certificate that is verified by your default CA. You may need to do:# cd /etc/ssl/client # openssl s_client -connect goliath:443 \ -cert ./david.crt -key ./david.key
If goliath's certificate is self-signed; you just slap the cert onto the bundle.ca so you can recognize it as a client. At this point, you should be able to wget a file, too:# openssl s_client -connect goliath:443 \ -CAfile /path/to/ca/bundle.ca \ -cert ./david.crt -key ./david.key
I've put the bundle thing in there; again, you won't need the --ca-certificate flag if goliath's server ssl cert is signed up a CA recognized in the wget default CA bundle. Now, more importantly, if you remove the --certificate and --private-key parts, that wget should FAIL, giving you an error something like this:# wget --certificate=/etc/ssl/client/david.crt \ --private-key=/etc/ssl/client/david.key \ --ca-certificate=/path/to/ca/bundle.ca \ https://goliath/file.html
Because, of course, goliath rejects you if you don't have that client cert it has signed. Anyhow, that's it. Hope someone finds that useful, as I had to waste a couple hours figuring out all the ins and outs.OpenSSL: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure Closed fd 3 Unable to establish SSL connection.