通过https进行的客户端证书身份验证失败

时间:2014-02-27 16:57:59

标签: python python-2.7 ssl

我正在尝试使用Python 2.7中的this sample code来运行https客户端身份验证。不幸的是,客户端脚本似乎没有正确验证,我无法找到原因。

我按如下方式生成了测试CA和服务器/客户端证书:

# 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

现在,如果我生成PKCS#12证书:

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

...并将testclient.p12导入Firefox,我可以按预期浏览测试站点,因此服务器和密钥似乎配置正确。但是,在尝试上面引用的示例代码时,如下所示:

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()

...我收到403错误:

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

我哪里误入歧途?

编辑:这是网站的Apache配置:

<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>

2 个答案:

答案 0 :(得分:2)

我认为这不是证书问题。 HTTP 403(Forbidden)已经是http服务器通过安全通道发送给你的http状态代码,因此ssl似乎工作正常。您只是想尝试访问未经授权的内容。

附加说明:也在浏览器中检查相同的网址!

答案 1 :(得分:1)

如果你需要python中的客户端,你可以使用requests,特别是this

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

print resp.status_code
print resp.text