Search code examples
pythonsslhttplib2

SSL version in httplib2 - EOF occurred in violation of protocol


I'm issuing a HTTPS GET request to a REST service I own with httplib2 but we're getting the error:

[Errno 8] _ssl.c:504: EOF occurred in violation of protocol

All other clients works well (browser, Java client, etc...) with the minor exception that PHP curl needed to be set to use SSL v3.

I've searched around and it seems that it is indeed an error regarding SSL version, but I can't seem to find a way to change it in httplib2. Is there any way around it besides changing the following line in the source code:

# We should be specifying SSL version 3 or TLS v1, but the ssl module
# doesn't expose the necessary knobs. So we need to go with the default
# of SSLv23.
return ssl.wrap_socket(sock, keyfile=key_file, certfile=cert_file,
                       cert_reqs=cert_reqs, ca_certs=ca_certs)

Solution

  • I developed this workaround for httplib2 :

    import httplib2
    
    # Start of the workaround for SSL3
    # This is a monkey patch / module function overriding 
    # to allow pages that only work with SSL3
    
    # Build the appropriate socket wrapper for ssl
    try:
        import ssl # python 2.6
        httplib2.ssl_SSLError = ssl.SSLError
        def _ssl_wrap_socket(sock, key_file, cert_file,
                             disable_validation, ca_certs):
            if disable_validation:
                cert_reqs = ssl.CERT_NONE
            else:
                cert_reqs = ssl.CERT_REQUIRED
            # Our fix for sites the only accepts SSL3
            try:
                # Trying SSLv3 first
                tempsock = ssl.wrap_socket(sock, keyfile=key_file, certfile=cert_file,
                                           cert_reqs=cert_reqs, ca_certs=ca_certs,
                                           ssl_version=ssl.PROTOCOL_SSLv3)
            except ssl.SSLError, e:
                tempsock = ssl.wrap_socket(sock, keyfile=key_file, certfile=cert_file,
                                           cert_reqs=cert_reqs, ca_certs=ca_certs,
                                           ssl_version=ssl.PROTOCOL_SSLv23)
            return tempsock
        httplib2._ssl_wrap_socket = _ssl_wrap_socket
    except (AttributeError, ImportError):
        httplib2.ssl_SSLError = None
        def _ssl_wrap_socket(sock, key_file, cert_file,
                             disable_validation, ca_certs):
            if not disable_validation:
                raise httplib2.CertificateValidationUnsupported(
                        "SSL certificate validation is not supported without "
                        "the ssl module installed. To avoid this error, install "
                        "the ssl module, or explicity disable validation.")
            ssl_sock = socket.ssl(sock, key_file, cert_file)
            return httplib.FakeSocket(sock, ssl_sock)
        httplib2._ssl_wrap_socket = _ssl_wrap_socket
    
    # End of the workaround for SSL3
    
    if __name__ == "__main__":
        h1 = httplib2.Http()
        resp, content = h1.request("YOUR_SSL3_ONLY_LINK_HERE", "GET")
        print(content)
    

    This workaround was based on the workarounds for urllib2 presented at this bug report http://bugs.python.org/issue11220,

    Update: Presenting a solution for httplib2. I didn't notice you were using httplib2, I thought it was urllib2.