Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added ability to choose SSL version #900

Closed
wants to merge 4 commits into from

3 participants

David Andrzejewski Kenneth Reitz Ian Cordasco
David Andrzejewski

This also acts as a workaround for #827, which in some cases, if you are
connecting to an SSL server that does not support SSLv2 or SSLv3 (and,
for exapmle, only supports TLSv1), would cause an illegal EOL SSL error.
If you select the right SSL protocol version, you won't see this error.

Kenneth, it looks like you tried to fix this in a previous revision by hard-coding the SSL version, and then you rolled it back. This makes it configurable via parameter to requests.requesttype()

David Andrzejewski dandrzejewski Added ability to choose SSL version
This also acts as a workaround for #827, which in some cases, if you are
connecting to an SSL server that does not support SSLv2 or SSLv3 (and,
for exapmle, only supports TLSv1), would cause an illegal EOL SSL error.
If you select the right SSL protocol version, you won't see this error.
2f414d0
Ian Cordasco

Pretty sure this is entirely unnecessary

Oh, just set it directly?

Collaborator

Good call. I'm so accustomed from Java to automatically writing getters/setters for everything. I'll go ahead and get that updated.

Collaborator

I did not already know, so thanks! This is actually the very first time I've ever done anything on GitHub.

Collaborator
David Andrzejewski

I made one last change to correct an issue where you could have a crash if Python was built without SSL support.

Also, I've submitted all of these changes to the urllib3 project, and it looks like @shazow is interested in merging, so you should be good there.

David Andrzejewski dandrzejewski reopened this
David Andrzejewski

Interesting - build 802 failed because it timed out after 15 minutes. 803 succeeded, but it finished before 802. So, this pull request is being reported as a failure when it shouldn't be...

Kenneth Reitz

I won't be merging this at this time. Requests should be able to automatically fall back, just like the web browser.

I'll be adding TransportAdapters soon, and you'll be able to specify advanced options like this.

David Andrzejewski

That's the problem. In my environment, on Windows (but not Linux), when I'm connecting to to an HTTPS server that only supports TLSv1/2/3, but NOT SSLv2/3, I get the same error that's reported in #827:

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

That's why I submitted this as a workaround.

Kenneth Reitz

I'll be adding TransportAdapters soon, and you'll be able to specify advanced options like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 19, 2012
  1. David Andrzejewski

    Added ability to choose SSL version

    dandrzejewski authored
    This also acts as a workaround for #827, which in some cases, if you are
    connecting to an SSL server that does not support SSLv2 or SSLv3 (and,
    for exapmle, only supports TLSv1), would cause an illegal EOL SSL error.
    If you select the right SSL protocol version, you won't see this error.
  2. David Andrzejewski
  3. David Andrzejewski
Commits on Oct 22, 2012
  1. David Andrzejewski
This page is out of date. Refresh to see the latest.
10 requests/models.py
View
@@ -64,7 +64,8 @@ def __init__(self,
_poolmanager=None,
verify=None,
session=None,
- cert=None):
+ cert=None,
+ ssl_version=None):
#: Dictionary of configurations for this request.
self.config = dict(config or [])
@@ -157,6 +158,9 @@ def __init__(self,
#: SSL Verification.
self.verify = verify
+ #: SSL Version
+ self.ssl_version = ssl_version
+
#: SSL Certificate
self.cert = cert
@@ -598,6 +602,10 @@ def send(self, anyway=False, prefetch=None):
else:
conn.cert_file = self.cert
+ if self.ssl_version:
+ if self.ssl_version is not None:
+ conn.ssl_version = self.ssl_version
+
if not self.sent or anyway:
# Skip if 'cookie' header is explicitly set.
17 requests/packages/urllib3/connectionpool.py
View
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
"""
cert_reqs = None
ca_certs = None
+ ssl_version = None
def set_cert(self, key_file=None, cert_file=None,
cert_reqs='CERT_NONE', ca_certs=None):
@@ -98,7 +99,8 @@ def connect(self):
# trusted_root_certs
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=self.cert_reqs,
- ca_certs=self.ca_certs)
+ ca_certs=self.ca_certs,
+ ssl_version=self.ssl_version)
if self.ca_certs:
match_hostname(self.sock.getpeercert(), self.host)
@@ -493,8 +495,8 @@ class HTTPSConnectionPool(HTTPConnectionPool):
:class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates,
instead of :class:httplib.HTTPSConnection`.
- The ``key_file``, ``cert_file``, ``cert_reqs``, and ``ca_certs`` parameters
- are only used if :mod:`ssl` is available and are fed into
+ The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, and ``ssl_version``
+ parameters are only used if :mod:`ssl` is available and are fed into
:meth:`ssl.wrap_socket` to upgrade the connection socket into an SSL socket.
"""
@@ -504,7 +506,7 @@ def __init__(self, host, port=None,
strict=False, timeout=None, maxsize=1,
block=False, headers=None,
key_file=None, cert_file=None,
- cert_reqs='CERT_NONE', ca_certs=None):
+ cert_reqs='CERT_NONE', ca_certs=None, ssl_version=None):
super(HTTPSConnectionPool, self).__init__(host, port,
strict, timeout, maxsize,
@@ -513,6 +515,7 @@ def __init__(self, host, port=None,
self.cert_file = cert_file
self.cert_reqs = cert_reqs
self.ca_certs = ca_certs
+ self.ssl_version = ssl_version
def _new_conn(self):
"""
@@ -532,6 +535,12 @@ def _new_conn(self):
connection = VerifiedHTTPSConnection(host=self.host, port=self.port)
connection.set_cert(key_file=self.key_file, cert_file=self.cert_file,
cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
+
+ if self.ssl_version is None:
+ connection.ssl_version = ssl.PROTOCOL_SSLv23
+ else:
+ connection.ssl_version = self.ssl_version
+
return connection
13 requests/sessions.py
View
@@ -58,7 +58,7 @@ class Session(object):
__attrs__ = [
'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks',
- 'params', 'config', 'verify', 'cert', 'prefetch']
+ 'params', 'config', 'verify', 'cert', 'prefetch', 'ssl_version']
def __init__(self,
headers=None,
@@ -71,7 +71,8 @@ def __init__(self,
config=None,
prefetch=True,
verify=True,
- cert=None):
+ cert=None,
+ ssl_version=None):
self.headers = from_key_val_list(headers or [])
self.auth = auth
@@ -83,6 +84,7 @@ def __init__(self,
self.prefetch = prefetch
self.verify = verify
self.cert = cert
+ self.ssl_version = ssl_version
for (k, v) in list(defaults.items()):
self.config.setdefault(k, deepcopy(v))
@@ -133,7 +135,8 @@ def request(self, method, url,
config=None,
prefetch=None,
verify=None,
- cert=None):
+ cert=None,
+ ssl_version=None):
"""Constructs and sends a :class:`Request <Request>`.
Returns :class:`Response <Response>` object.
@@ -154,6 +157,7 @@ def request(self, method, url,
:param prefetch: (optional) whether to immediately download the response content. Defaults to ``True``.
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
+ :param ssl_version: (optional) The SSL protocol version to use.
"""
method = str(method).upper()
@@ -192,7 +196,8 @@ def request(self, method, url,
prefetch=prefetch,
verify=verify,
cert=cert,
- _poolmanager=self.poolmanager
+ _poolmanager=self.poolmanager,
+ ssl_version=ssl_version
)
# merge session cookies into passed-in ones
Something went wrong with that request. Please try again.