Python client certificate authentication over https is failing
Question: I'm attempting to get https client authentication working using [this sample
code](http://stackoverflow.com/a/4464435/789671) in Python 2.7. Unfortunately,
the client script doesn't appear to be authenticating correctly and I've not
been able to track down why.

I generated a test CA and server/client certificates as follows:

    
    
    # Generate CA key and certificate
    openssl genrsa -des3 -out test.ca.key 8192
    openssl req -new -key test.ca.key -x509 -days 30 -out test.ca.crt
    
    # Generate server key and certificate
    openssl genrsa -out www.testsite.com.key 1024
    openssl req -new -key www.testsite.com.key -out www.testsite.com.csr
    openssl x509 -req -days 30 -in www.testsite.com.csr -CA test.ca.crt -CAkey test.ca.key -CAcreateserial -out www.testsite.com.crt
    
    # Generate client key and certificate
    openssl genrsa -out testclient.key 1024
    openssl req -new -key testclient.key -out testclient.csr
    openssl x509 -req -days 30 -in testclient.csr -CA test.ca.crt -CAkey test.ca.key -CAcreateserial -out testclient.crt
    

Now if I generate a PKCS#12 certificate:

    
    
    openssl pkcs12 -export -clcerts -in testclient.crt -inkey testclient.key -out testclient.p12
    

...and import testclient.p12 into Firefox, I can browse the test site as
expected, so the server and keys would appear to be configured properly.
However, when trying the sample code referenced above, as follows:

    
    
    import urllib2, httplib
    
    class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
        def __init__(self, key, cert):
            urllib2.HTTPSHandler.__init__(self)
            self.key = key
            self.cert = cert
        def https_open(self, req):
            return self.do_open(self.getConnection, req)
        def getConnection(self, host, timeout=300):
            return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert)
    
    opener = urllib2.build_opener(HTTPSClientAuthHandler('testclient.key', 'testclient.crt') )
    response = opener.open("https://www.testsite.com/")
    print response.read()
    

... I get a 403 error:

    
    
    Traceback (most recent call last):
      File "./cert2.py", line 21, in <module>
        response = opener.open("https://www.testsite.com/")
      File "/usr/lib64/python2.6/urllib2.py", line 395, in open
        response = meth(req, response)
      File "/usr/lib64/python2.6/urllib2.py", line 508, in http_response
        'http', request, response, code, msg, hdrs)
      File "/usr/lib64/python2.6/urllib2.py", line 433, in error
        return self._call_chain(*args)
      File "/usr/lib64/python2.6/urllib2.py", line 367, in _call_chain
        result = func(*args)
      File "/usr/lib64/python2.6/urllib2.py", line 516, in http_error_default
        raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
    urllib2.HTTPError: HTTP Error 403: Forbidden
    

Where did I go astray?

EDIT: Here's the site's Apache config:

    
    
    <VirtualHost *:80>
      ServerAdmin webmaster@testsite.com
      ServerName www.testsite.com
    
      DocumentRoot /var/www/testsite/
      <Directory "/">
        Options FollowSymLinks
        AllowOverride None
      </Directory>
    
      RewriteEngine On
      RewriteCond %{SERVER_PORT} 80
      RewriteRule ^/?(.*) https://www.testsite.com/$1 [L]
    
      ErrorLog ${APACHE_LOG_DIR}/error.log
      LogLevel warn
      CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
    
    <VirtualHost *:443>
      ServerAdmin webmaster@testsite.com
    
      DocumentRoot /var/www/testsite/
      ServerName www.testsite.com
    
      SSLEngine on
      SSLCertificateFile    /etc/ssl/certs/www.testsite.com.crt
      SSLCertificateKeyFile /etc/ssl/private/www.testsite.com.key
      SSLCertificateChainFile /etc/ssl/ca/test.ca.crt
      SSLCACertificateFile /etc/ssl/ca/test.ca.crt
    
      <Location />
        SSLRequireSSL
        SSLVerifyClient require
        SSLVerifyDepth 10
      </Location>
    
      <Directory />
        Options FollowSymLinks
        AllowOverride None
      </Directory>
      <Directory /var/www/testsite>
        Options FollowSymLinks MultiViews
        AllowOverride None
        Order allow,deny
        allow from all
      </Directory>
    
      ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/testsite/
      <Directory "/usr/lib/cgi-bin/testsite">
        AllowOverride None
        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
        Order allow,deny
        Allow from all
      </Directory>
    
      ErrorLog /var/log/apache2/error.log
      LogLevel warn
      CustomLog /var/log/apache2/access.log combined
    </VirtualHost>
    


Answer: I think this isn't a cert issue. HTTP 403 (Forbidden) is already a http status
code sent to you by the http server through the secured channel, so ssl seems
to work fine. You are just trying to access something you are not authorized
for.

Additional note: Check the same url in a browser too!

