Eric Norman from the University of Wisconsin graciously contributed the following writeup about an elegant way to enable PKI authentication for web applications (which he implemented for Geeklog).

Mark Franklin at Dartmouth asked to to write up what I did to
enable use of client certificates for an application.  Here it comes.

The application is a collaborative tool used by a hundred or so
folks hereabouts and thereabouts and called Geeklog (www.geeklog.net).
It's written in php and we run it on a Macintosh with OSX (panther,
the latest).  Geeklog has its own set of user identifiers (screennames)
and they aren't the same as the "normal" identifiers used here at the
university (and they can't be for the thereabouts folks).  I also
needed to do this such that possession of a client certificate is
sufficient, but not necessary; if someone doesn't have one,
username/password must still be possible.

I'll start with the shock and awe: I did the authentication part by
making *zero* modifications to the geeklog code.

First the server.  OSX comes with an Apache web server and mod_ssl.
Apple also provides a web-based interface for administration.  This
interface does not yet have support for enabling client certificate
requests during the SSL handshake.  Here's what the SSL configuration
looks like:
       <IfModule mod_ssl.c>
               SSLEngine On
               SSLLog "/private/var/log/httpd/ssl_engine_log"
               SSLCertificateChainFile "/LAN/Users/ejnorman/vidi_chain.pem"
               SSLCertificateFile "/LAN/Users/ejnorman/vidi_cert.pem"
               SSLCertificateKeyFile "/LAN/Users/ejnorman/vidi_key.pem"
               SSLCipherSuite "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:!SSLv2:+EXP:+eNULL"

               SSLCACertificateFile "/LAN/Users/ejnorman/vidi_trust.pem"
               SSLVerifyDepth 5
               SSLOptions +StdEnvVars +ExportCertData
               SSLVerifyClient optional
       </IfModule>
The last four SSL... lines are what enables client certificate requests.
(Yes, I know stuff shouldn't be in my home directory; this will be fixed).
Anyway, these 4 lines were inserted manually.  The good news is that use
of Apple's administration interface doesn't mess with them (and better
news is that it even knows about them since it preserved them but
rearranged their order).

All the above is just to configure mod_ssl to request a client certificate;
it has nothing to do with the geeklog code.

Now for the "magic".  I wrote a separate php file that you execute by
using a separate URL; i.e. https://archlog.doit.wisc.edu/cert gets
you to my php code.  This code:

(1) extracts the email address form the client certificate (mod_ssl
   puts it in an environment variable),
(2) uses that to query the geeklog user database and extract the
   geeklog username (geeklog uses mysql and the user table contains
   both username and email address along with other stuff),
(3) creates a session for that user (geeklog has a function to do that;
   sessions are maintained in a session table of the mysql database),
(4) creates a cookie containing the session identifier (that's how
   geeklog maintains session information), and
(5) redirects to the regular geeklog HTML producing php code.

When the regular geeklog code runs, it notices the cookie, notices that
it has a session with that identifier, and concludes "user already logged
in"!

If anything fails during the above, e.g. no SSL, no client certificate
supplied, no row in database matching email address, etc, then
neither a session nor a cookie is created before going to the regular
geeklog code.

Observations:

+ This "trick" will work with lots of different web-based applications;
 all you have to do is figure out how a session is maintained.
+ You might also have to figure out a different URL for the
 redirection that bypasses the username/password prompt; I didn't in
 the geeklog case.  This will work regardless of whether session
 identifiers are passed around with cookies, in URLs, or via hidden
 variables.
+ The separate URL could be eliminated by one "well placed if statement".
+ This scheme does not mean that all users with certificates that are
 trusted by the server are allowed to use geeklog; they also have to
 register with geeklog to get into the user table.
+ Registration of geeklog users via X.509 certificates is not addressed.
+ Reconfiguring mod_ssl to also trust certificates from thereabouts
 is all it will take to include those folks too (along with their
 registration, which they have to do anyway).

Now I did add about two lines of geeklog code to propagate the "https"
in URLs that appear in links and form actions as you continue with the
geeklog code.  However, since there aren't any confidentiality concerns
in this case, this wouldn't be necessary.  I'll leave it as an exercise
for the reader to figure out why not.

One of the things this leads me to wonder about is if it would be better
to focus on the concept of session instead of things like authentication,
etc.  Some questions that might be pertinent are:

+ What information is contained in a session?
+ What needs to happen pre-session?
+ What needs to happen during a session?
+ What can happen during a session (browser fails? back button pushed?)
+ What needs to happen post-session?
+ What parts of the "session concept" are common to just about everyone?