Once server side certificates have been set up, setting up client side certificates requires some additional configuration, especially if you want to use them as the source of identity in your applications.
First, the application needs the additional directive in its /etc/httpd/conf.d specific file.
Did that work for you? NO…me neither…
OK, so actually, it was slightly more involved. First, I had to figure out how to turn on NSS debugging. That is done by editing the file
and setting the value for
Once that worked, I saw messages in /var/log/httpd/error_log that looked like:
[Fri Mar 30 11:43:54 2012] [debug] nss_engine_kernel.c(309): Changed client verification type will force renegotiation [Fri Mar 30 11:43:54 2012] [info] Requesting connection re-negotiation [Fri Mar 30 11:43:54 2012] [debug] nss_engine_kernel.c(404): Performing full renegotiation: complete handshake protocol [Fri Mar 30 11:43:54 2012] [debug] nss_engine_kernel.c(418): Re-negotation request failed: returned error -12176
So I enabled renegotiation. Again, editing /etc/httpd/conf.d/nss.conf
NSSRenegotiation on NSSRequireSafeNegotiation on
And then client side certs worked for me. They probably won’t work for you, though.
In between, I set up a Dogtag PKI instance, generated a new server side certificate, a client side certificate for my browser, and installed the CA and Server side certificate in my web server.
I don’t think all of that was necessary.
A variation would have been to generate a client side certificate and sign it with the self-sign CA key that my web server was already using. The bottom line is that the browser and the server need to both trust the CAs used for the client and server certs.
Ok, so we’ve established a secure channel. This doesn’t mean much if we don’t know who the user is at the application level. The NSS layer follows the SSL approach of using the option: FakeBasicAuth to pass information from the Certificate through to the application. I uncommented the line:
NSSOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire
You also need to tell NSS which value from the certificate should be passed as the user. In my case, it is the Subject:uid value, so I configured mine as:
The overall difference in the nss.conf file is:
--- /etc/httpd/conf.d/nss.conf.orig 2012-03-29 12:59:06.319470425 -0400 +++ /etc/httpd/conf.d/nss.conf 2012-03-30 16:21:24.836124822 -0400 @@ -17,7 +17,7 @@ # Note: Configurations that use IPv6 but not IPv4-mapped addresses need two # Listen directives: "Listen [::]:8443" and "Listen 0.0.0.0:443" # -Listen 8443 +Listen 443 ## ## SSL Global Context @@ -71,17 +71,17 @@ # # Only renegotiate if the peer's hello bears the TLS renegotiation_info # extension. Default off. -NSSRenegotiation off +NSSRenegotiation on # Peer must send Signaling Cipher Suite Value (SCSV) or # Renegotiation Info (RI) extension in ALL handshakes. Default: off -NSSRequireSafeNegotiation off +NSSRequireSafeNegotiation on ## ## SSL Virtual Host Context ## -
+ # General setup for the virtual host #DocumentRoot "/etc/httpd/htdocs" @@ -92,7 +92,7 @@ # LogLevel is not inherited from httpd.conf. ErrorLog /etc/httpd/logs/error_log TransferLog /etc/httpd/logs/access_log -LogLevel warn +LogLevel debug # SSL Engine Switch: # Enable/Disable SSL for this virtual host. @@ -198,7 +198,8 @@ # o OptRenegotiate: # This enables optimized SSL connection renegotiation handling when SSL # directives are used in per-directory context. -#NSSOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire +NSSOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire +NSSUserName SSL_CLIENT_S_DN_UID NSSOptions +StdEnvVars
Now a little bit of Python/WSGI specifics
For my WSGI application, I add in a value that says “pass on the authentication info to the application”
Then the WSGI app can access the value via:
class Application(BaseApplication): @webob.dec.wsgify def __call__(self, req): context['remote_user'] = req.environ.get('REMOTE_USER')
Here is what my file /etc/httpd/conf.d/keystone.conf looks like to protect the suburl “main”:
WSGIScriptAlias /main /var/www/wsgi/httpdmain.py WSGIScriptAlias /admin /var/www/wsgi/httpdadmin.py < Location "/main" > NSSRequireSSL NSSVerifyClient require WSGIPassAuthorization On < / Location >