Reputation: 7840
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 [email protected]
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 [email protected]
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>
Upvotes: 4
Views: 9319
Reputation: 161
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
Upvotes: 1
Reputation: 3726
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!
Upvotes: 2