Python 2.7.9 TLS客户端身份验证

时间:2015-09-22 23:36:32

标签: python sockets ssl client-certificates httplib

存在一个具有RESTful API的服务器,该API通过PUT接受新内容。此服务要求客户​​端提供用于对数据推送进行身份验证和授权的有效服务器证书。使用Python 2.7.9我根据使用httplib和ssl模块找到的一些示例创建了我的客户端代码。

这是服务接受的数据格式的示例。这是一个有序的字典,因为他们要求按特定顺序推送字段:

data = OrderedDict([('Title','Test Title'),
                  ('Description','Test Description'),
                  ('AlertID','1234'),
                  ('TypeName','Test_Alert'),
                  ('Properties','<tag1>Tag1</tag1><tag2>Tag2</tag2>')
       ])

此数据通过PUT作为标准查询字符串传递,即https://host.domain/path/to/rest.php?Title=Test%20Title&Description= ...

我遇到的问题是我创建的代码收到401 Authorization Required错误状态。我已经验证我的服务器证书使用与远程系统相同的CA颁发者,两个系统上的CA捆绑包相同,并且远程系统管理员已经注意到他们已将我的公钥添加到其可信密钥链中。

这是我的客户端代码,也许有人可以检测到问题?

import socket
import ssl
import httplib
import urllib

host = 1.2.3.4
port = 443
rest_url = '/path/to/rest.php'
cert_file = '/path/to/server/cert.crt'
key_file = '/path/to/private/key.key'
ca_file = '/path/to/ca-bundle.crt'

class HTTPSClientAuthConnection(httplib.HTTPSConnection):

    def __init__(self, host, port, key_file, cert_file, ca_file, timeout=None):
        httplib.HTTPSConnection.__init__(self, host, key_file=key_file, cert_file=cert_file)
        self.key_file = key_file
        self.cert_file = cert_file
        self.ca_file = ca_file
        self.timeout = timeout

    def connect(self):
        sock = socket.create_connection((host, port), self.timeout)
        if self._tunnel_host:
            self.sock = sock
            self._tunnel()

        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ca_certs=self.ca_file, cert_reqs=ssl.CERT_REQUIRED)


if __name__ == '__main__':

    data = urllib.urlencode(data)
    conn = HTTPSClientAuthConnection(host, port, key_file=key_file, cert_file=cert_file, ca_file=ca_file)
    conn.request('PUT', rest_url, data)
    response = conn.getresponse()
    print response.status, response.reason
    data = response.read()
    print data
    conn.close() 

我也通过conn.set_debuglevel(1)启用了调试功能,这样我就可以看到标题和数据输出了。数据格式正确,标题虽然稀疏,但不应引起问题。我最初的想法是它没有发送正确的内容长度,可能是因为字典,但是,Content-Length似乎设置正确而Accept-Encoding默认为'identity'。

我还打印了套接字包装器以查看<SSLSocket object at 0x...>,这使我相信SSL套接字已成功建立。

最后,我已经执行了一个tcpdump,虽然它是加密的但我可以看到证书交换的部分,它正在验证发行者和诸如此类的东西,除此之外它都是加密的。

除此之外,也许是SNI?我必须检查远程服务器devs,但我知道Python 2不支持它。也许我应该尝试另一种途径来获得SSL功能,但是我对使用第三方模块犹豫不决,因为很难将这些内容放到我的环境中然后维护它,但是如果有更好的选择和好的例子让我知道。

谢谢!

0 个答案:

没有答案