4

I'm attempting to get https client authentication working using this sample code 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>
Community
  • 1
  • 1
glibdud
  • 7,550
  • 4
  • 27
  • 37
  • @dougzor No. I ended up simplifying my requirements and just using curl to accomplish what I needed. – glibdud May 22 '14 at 14:02

2 Answers2

2

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!

pasztorpisti
  • 3,760
  • 1
  • 16
  • 26
  • Thanks, I'm accessing the same URL that was requested in the browser test (which succeeded), though. – glibdud Feb 27 '14 at 18:11
  • @glibdud Do you need the `HTTPSClientAuthHandler`? In a lot of cases the client isn't authenticated at all. I guess you haven't set up your browser to support your client key for the server. – pasztorpisti Feb 27 '14 at 18:34
  • Yes, the server is configured to require client certificates, and it requests the certificate when I access the page via browser. In the browser I'm able to provide the certificate and gain access, but it isn't working via the included Python code. – glibdud Feb 27 '14 at 18:37
1

If you need a client in python you can use requests, in particular this.

import requests
resp = requests.get('https://www.testsite.com/', cert=('testclient.crt', 'testclient.key'))

print resp.status_code
print resp.text
Nicolas Malbran
  • 161
  • 2
  • 6