如何使用httplib2进行共同证书身份验证

时间:2010-03-02 12:41:10

标签: python ssl httplib2

我正在使用httplib2从我的服务器向另一个Web服务发出请求。我们想要使用相互证书身份验证。我看到如何使用证书进行传出连接(h.set_certificate),但如何检查应答服务器使用的证书?

This ticket似乎表明httplib2本身并不这样做,并且对于在哪里查看只有模糊的建议。

有可能吗?我是否需要在较低级别进行攻击?

2 个答案:

答案 0 :(得分:5)

以下是我的同事Dave St. Germain为解决问题所写的代码:

import ssl
import socket
from httplib2 import has_timeout
import httplib2
import socks


class CertificateValidationError(httplib2.HttpLib2Error):
    pass


def validating_sever_factory(ca_cert_file):
    # we need to define a closure here because we don't control
    # the arguments this class is instantiated with
    class ValidatingHTTPSConnection(httplib2.HTTPSConnectionWithTimeout):

        def connect(self):
            # begin copypasta from HTTPSConnectionWithTimeout
            "Connect to a host on a given (SSL) port."

            if self.proxy_info and self.proxy_info.isgood():
                sock = socks.socksocket(socket.AF_INET, socket.SOCK_STREAM)
                sock.setproxy(*self.proxy_info.astuple())
            else:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

            if has_timeout(self.timeout):
                sock.settimeout(self.timeout)
            sock.connect((self.host, self.port))
            # end copypasta


            try:
                self.sock = ssl.wrap_socket(sock,
                            self.key_file,
                            self.cert_file,
                            cert_reqs=ssl.CERT_REQUIRED,
                            ca_certs=ca_cert_file
                            )
            except ssl.SSLError:
                # we have to capture the exception here and raise later because 
                # httplib2 tries to ignore exceptions on connect
                import sys
                self._exc_info = sys.exc_info()
                raise
            else:
                self._exc_info = None

                # this might be redundant
                server_cert = self.sock.getpeercert()
                if not server_cert:
                    raise CertificateValidationError(repr(server_cert))

        def getresponse(self):
            if not self._exc_info:
                return httplib2.HTTPSConnectionWithTimeout.getresponse(self)
            else:
                raise self._exc_info[1], None, self._exc_info[2]
    return ValidatingHTTPSConnection


def do_request(url,
        method='GET',
        body=None,
        headers=None,
        keyfile=None,
        certfile=None,
        ca_certs=None,
        proxy_info=None,
        timeout=30):
    """
    makes an http/https request, with optional client certificate and server
    certificate verification.
    returns response, content
    """
    kwargs = {}
    h = httplib2.Http(proxy_info=proxy_info, timeout=timeout)
    is_ssl = url.startswith('https')
    if is_ssl and ca_certs:
        kwargs['connection_type'] = validating_sever_factory(ca_certs)

    if is_ssl and keyfile and certfile:
        h.add_certificate(keyfile, certfile, '')
    return h.request(url, method=method, body=body, headers=headers, **kwargs)

答案 1 :(得分:3)

自问题以来,事情可能已经发生了变化,我可以使用httplib2 v0.7进行相互身份验证,如下所示:

import httplib2

h=httplib2.Http(ca_certs='ca.crt')
h.add_certificate(key='client_private_key.pem', cert='cert_client.pem', domain='')
try: resp, cont = h.request('https://mytest.com/cgi-bin/test.cgi')
except Exception as e: print e

注意domain=''参数,这是我能使它工作的唯一方法