Making SSL work with Apache 2 on Mac OS X with CAcert

Getting SSL up and running on OS X is not too difficult these days. First you need to tell it to read the SSL config file (removing red lines, adding green lines):

— /etc/apache2/httpd.conf 2008-06-11 03:42:25.000000000 +0200
+++ /etc/apache2/httpd.conf.dist 2008-06-11 04:15:15.000000000 +0200
@@ -470,7 +470,7 @@
#Include /private/etc/apache2/extra/httpd-default.conf

# Secure (SSL/TLS) connections
-#Include /private/etc/apache2/extra/httpd-ssl.conf
+Include /private/etc/apache2/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
# starting without SSL on platforms with no /dev/random equivalent

Then you need to fix this config file for your environment:

— /private/etc/apache2/extra/httpd-ssl.conf.dist 2008-06-11 03:43:21.000000000 +0200
+++ /private/etc/apache2/extra/httpd-ssl.conf 2008-06-11 04:03:50.000000000 +0200
@@ -22,9 +22,9 @@
# Manual for more details.
#
#SSLRandomSeed startup file:/dev/random 512
-#SSLRandomSeed startup file:/dev/urandom 512
+SSLRandomSeed startup file:/dev/urandom 512
#SSLRandomSeed connect file:/dev/random 512
-#SSLRandomSeed connect file:/dev/urandom 512
+SSLRandomSeed connect file:/dev/urandom 512

#
@@ -75,8 +75,8 @@

General setup for the virtual host

DocumentRoot “/Library/WebServer/Documents”
-ServerName http://www.example.com:443
-ServerAdmin you@example.com
+ServerName secure.samj.net:443
+ServerAdmin xxxx@samj.net
ErrorLog “/private/var/log/apache2/error_log”
TransferLog “/private/var/log/apache2/access_log”

@@ -125,6 +125,7 @@

Makefile to update the hash symlinks after changes.

#SSLCACertificatePath “/private/etc/apache2/ssl.crt”
#SSLCACertificateFile “/private/etc/apache2/ssl.crt/ca-bundle.crt”
+SSLCACertificateFile “/private/etc/apache2/server-ca.crt”

Certificate Revocation Lists (CRL):

Set the CA revocation path where to find CA CRLs for client

@@ -143,6 +144,8 @@

issuer chain before deciding the certificate is not valid.

#SSLVerifyClient require
#SSLVerifyDepth 10
+SSLVerifyClient require
+SSLVerifyDepth 2

Access Control:

With SSLRequire you can do per-directory access control based

Notice that I’m using client certificates for authentication but you can comment out the SSLCACertificateFile, SSLVerifyClient and SSLVerifyDepth options if you don’t need this. If you do you’ll want to grab the root from CAcert:

# curl -o server-ca.crt https://www.cacert.org/certs/root.crt

You’ll want to generate random nubmers (key) and a certificate signing request (csr) in order to get a certificate (crt) file, and despite most information on the topic this can be done in one command:

# openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csrGenerating a 2048 bit RSA private key
………+++
……………………………………………………………+++
writing new private key to ‘server.key’
—–
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
—–
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:New South Wales
Locality Name (eg, city) []:Sydney
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Australian Online Solutions Pty Ltd
Organizational Unit Name (eg, section) []:Security
Common Name (eg, YOUR name) []:secure.samj.net
Email Address []:xxxx@samj.net

Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Actually in the case of CAcert.org everything except the common name is ignored so you can leave it as defaults.

For testing we’ll use a script which prints all the environment variables (this is what I was after for my certificate authentication anyway):

# cat /Library/WebServer/CGI-Executables/printenv
#!/bin/bash
echo “Content-type: text/plain”
echo “”
printenv

And when you browse to your machine (eg https://secure.samj.net/) you should see something like this:

SSL_SERVER_A_KEY=rsaEncryption
SSL_CLIENT_VERIFY=SUCCESS
SSL_SESSION_ID=A6C2F73FBFBB30AF927947D03B8E61AF26E0C4C68CB98F3B9CB7EB6E6ED78147
SERVER_SIGNATURE=
SSL_CLIENT_S_DN_Email=xxxx@debian.org
SSL_CLIENT_A_SIG=sha1WithRSAEncryption
SSL_CLIENT_I_DN_Email=support@cacert.org
HTTP_KEEP_ALIVE=300
SSL_VERSION_LIBRARY=OpenSSL/0.9.7l
HTTP_USER_AGENT=Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-GB; rv:1.9) Gecko/2008053008 Firefox/3.0
SERVER_PORT=443
HTTP_HOST=secure.samj.net
SSL_CIPHER_ALGKEYSIZE=256
SSL_SERVER_I_DN=/O=CAcert Inc./OU=http://www.CAcert.org/CN=CAcert Class 3 Root
SSL_CLIENT_M_VERSION=3
DOCUMENT_ROOT=/Library/WebServer/Documents
HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7
SCRIPT_FILENAME=/Library/WebServer/CGI-Executables/printenv
HTTPS=on
REQUEST_URI=/cgi-bin/printenv
SSL_SERVER_I_DN_OU=http://www.CAcert.org
SSL_CLIENT_A_KEY=rsaEncryption
SCRIPT_NAME=/cgi-bin/printenv
SSL_SERVER_S_DN=/CN=secure.samj.net
SSL_VERSION_INTERFACE=mod_ssl/2.2.8
SSL_CLIENT_I_DN_OU=http://www.cacert.org
SSL_CIPHER_EXPORT=false
HTTP_CONNECTION=keep-alive
SSL_SERVER_I_DN_O=CAcert Inc.
SSL_CLIENT_S_DN=/CN=Sam Johnston/emailAddress=xxxx@debian.org/emailAddress=xxxx@samj.net/emailAddress=66e1c629ca065f0cead0ac9bee8e4cb016f93cb7
SSL_COMPRESS_METHOD=NULL
REMOTE_PORT=50392
PATH=/usr/bin:/bin:/usr/sbin:/sbin
SSL_CLIENT_I_DN_O=Root CA
SSL_CLIENT_M_SERIAL=0551B7
SSL_CIPHER=DHE-RSA-AES256-SHA
PWD=/Library/WebServer/CGI-Executables
SERVER_ADMIN=xxxx@samj.net
SSL_SERVER_A_SIG=sha1WithRSAEncryption
SSL_CLIENT_V_START=Jun 11 01:38:03 2008 GMT
SSL_SERVER_M_SERIAL=56C8
SSL_PROTOCOL=SSLv3
SSL_CLIENT_I_DN_CN=CA Cert Signing Authority
HTTP_ACCEPT_LANGUAGE=en-gb,en;q=0.5
SSL_SERVER_S_DN_CN=secure.samj.net
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
REMOTE_ADDR=::1
SHLVL=1
SERVER_NAME=secure.samj.net
SSL_SERVER_M_VERSION=3
HTTP_PRAGMA=no-cache
SSL_CLIENT_V_END=Jun 11 01:38:03 2010 GMT
SERVER_SOFTWARE=Apache/2.2.8 (Unix) mod_ssl/2.2.8 OpenSSL/0.9.7l DAV/2
QUERY_STRING=
SERVER_ADDR=::1
SSL_SERVER_V_END=Jun 11 01:48:07 2010 GMT
SSL_CLIENT_I_DN=/O=Root CA/OU=http://www.cacert.org/CN=CA Cert Signing Authority/emailAddress=support@cacert.org
SSL_CLIENT_S_DN_CN=Sam Johnston
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
HTTP_CACHE_CONTROL=no-cache
HTTP_ACCEPT_ENCODING=gzip,deflate
SSL_SERVER_I_DN_CN=CAcert Class 3 Root
REQUEST_METHOD=GET
HTTP_COOKIE=__utma=64622253.189158232302809900.1213012569.1213012569.1213087976.2; __utmz=64622253.1213012569.1.1.utmcsr=blogger.com|utmccn=(referral)|utmcmd=referral|utmcct=/rearrange
SSL_SERVER_V_START=Jun 11 01:48:07 2008 GMT
SSL_CLIENT_V_REMAIN=730
SSL_CIPHER_USEKEYSIZE=256
_=/usr/bin/printen

That’s it for this morning’s lesson.