PKI Enabling an Apache Web Server

Once all of the required SSL certificates have been created (or obtained via enterprise channels) it is relatively easy to enable Client-side SSL authentication on an Apache webserver.

The server needs to have mod_ssl installed, and the site needs to be set up to use SSL. The important bits here are that the various SSLCertificate options are set correctly to use locally installed copies of the published CA and Server Certificates.

This is an example <VirtualHost> container in /etc/httpd/conf.d/ssl.conf that implements a signed SSL chain to verify the Server. It enforces Client PKI in that without a valid client certificate, access to the SSL website is denied.

<VirtualHost *:443>
    # Use separate log files for the SSL virtual host; note that LogLevel is not inherited from httpd.conf.
    ErrorLog logs/ssl_error_log
    TransferLog logs/ssl_access_log
    LogLevel warn
    # Enable SSL for this virtual host.
    SSLEngine on
    SSLProtocol all -SSLv2
    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
    # Server Certificate:
    SSLCertificateFile /etc/pki/tls/certs/host1.website.org.crt
    SSLCertificateKeyFile /etc/pki/tls/private/host1.website.org.key
    SSLCertificateChainFile /etc/pki/tls/certs/tls-ca-chain.pem
    SSLCACertificateFile /etc/pki/tls/certs/tls-ca-chain.pem
    # Client Authentication:
    SSLVerifyClient optional
    SSLVerifyDepth  4
    SSLUserName SSL_CLIENT_S_DN_CN
    # If Client Certificate is not valid, send user to an error page.
    RewriteEngine On
    RewriteCond %{SSL:SSL_CLIENT_VERIFY} !^SUCCESS$
    RewriteRule .* /ssl-client-auth-required.html [L]
    # Allow extraction of attributes from user certificates
    # SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
    <Files ~ "\.(cgi|shtml|phtml|php3?)$">
        SSLOptions +StdEnvVars
    </Files>
    <Directory "/var/www/cgi-bin">
        SSLOptions +StdEnvVars
    </Directory>
    # SSL Protocol Adjustments:
    SetEnvIf User-Agent ".*MSIE.*"nokeepalive ssl-unclean-shutdowndowngrade-1.0 force-response-1.0
    # Per-Server Logging:
    CustomLog "|/usr/sbin/rotatelogs /var/log/httpd/ssl_request_log 720""%h %l %{SSL_CLIENT_S_DN_CN}x %t %r %>s %b"
</VirtualHost>

The configuration above states that SSLVerifyClient is OPTIONAL. We have configured this particular server in a way that despite the requirement for a client cert being optional, it’s actually mandatory. The way this works is if we set SSLVerifyClient to REQUIRE, the session would terminate instantly on detection of an invalid certificate. Instead, we trap the fact that the cert is invalid in the RewriteCond statement, and redirect the user to an appropriate error page stating that PKI authentication is required.

The SSLUserName option populates the Apache REMOTE_USER variable with the CN from the certificate. We can set this to any available attribute, and the REMOTE_USER is a hook available to CGI/Perl/PHP pages to use for authorization if required. We also pull out the user’s CN from the client certificate and poke it into a custom formatted log entry.