Skip to content
This repository

Added ability to choose SSL version #109

Closed
wants to merge 4 commits into from

5 participants

David Andrzejewski Ian Cordasco Andrey Petrov Ken Schwencke Kevin Burke
David Andrzejewski

This is the same as a change that I did for the requests project - which
required this urllib3 change - so I thought it might be appropriate to
contribute the change to the upstream library as well.

David Andrzejewski Added ability to choose SSL protocol version
This is the same as a change that I did for the requests project - which
required this urllib3 change - so I thought it might be appropriate to
contribute the change to the upstream library as well.
5557476
Ian Cordasco

If you're submitting this here, you need to add unit tests so @shazow can sleep comfortably with 100% test coverage.

David Andrzejewski

I will try to, although I'm not sure how I can verify that it's actually using the chosen SSL protocol version.

David Andrzejewski

It looks like there's no easy way to check on that, and there's also no easy way to make Tornado start up and only support certain SSL versions. However, if I force SSLv2, it throws an exception, so I'll submit two new tests: One that forces it to TLSv1 (checks for a 200 response), and one that forces it to SSLv2 (checks for an SSLError exception)

Ian Cordasco

Hm, @shazow might have some insight on writing tests for this.

Andrey Petrov shazow commented on the diff
test/with_dummyserver/test_https.py
@@ -21,9 +22,21 @@ def setUp(self):
21 22
 
22 23
     def test_simple(self):
23 24
         r = self._pool.request('GET', '/specific_method',
24  
-                               fields={'method': 'GET'})
  25
+            fields={'method': 'GET'})
2
Andrey Petrov Owner
shazow added a note

Please keep indents (and other things) PEP8 style. :)

Whoops didn't catch that. I'll get it corrected!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
urllib3/connectionpool.py
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
76 76
     """
77 77
     cert_reqs = None
78 78
     ca_certs = None
  79
+    ssl_version = ssl.PROTOCOL_SSLv23
3
Andrey Petrov Owner
shazow added a note

This line will explode if ssl is None (see try/except header up top, not all platforms have Python compiled with SSL).

Andrey Petrov Owner
shazow added a note

Can we pass it in the same way we pass in cert_reqs and ca_certs?

I'm fine with assuming it's SSLv23 if ssl_version is None.

OK. I'll set ssl_version = None up top.

For the constructor, I'm assuming you'd rather I default ssl_version=None and then, in _new_conn(), check if self.ssl_version is None and set it there accordingly? That way, it'll be done after ssl has been checked for and SSLError raised.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Andrey Petrov shazow commented on the diff
urllib3/connectionpool.py
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
76 76
     """
77 77
     cert_reqs = None
78 78
     ca_certs = None
  79
+    ssl_version = None
2
Andrey Petrov Owner
shazow added a note

Why are we tracking ssl_version separately both in HTTPSConnectionPool and VerifiedHTTPSConnection? Shouldn't it be one or the other?

Doesn't HTTPSConnectionPool, pass it into VerifiedHTTPSConnection?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Andrey Petrov
Owner

Thanks for the fixes! A mention of the new ssl_version param in the docstring for HTTPSConnectionPool, or wherever we end up keeping, it would be great. :)

Thomas Weißschuh t-8ch referenced this pull request
Merged

add support for SNI #89

Andrey Petrov
Owner

Hrm. I'm getting this on OSX using Py27:

........................F..........................................................
======================================================================
FAIL: test_set_ssl_version_to_sslv2 (test.with_dummyserver.test_https.TestHTTPS)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/shazow/projects/urllib3/test/with_dummyserver/test_https.py", line 38, in test_set_ssl_version_to_sslv2
    fields={'method': 'GET'})
AssertionError: SSLError not raised
-------------------- >> begin captured logging << --------------------
urllib3.connectionpool: INFO: Starting new HTTPS connection (1): localhost
urllib3.connectionpool: DEBUG: "GET /specific_method?method=GET HTTP/1.1" 200 0
root: INFO: 200 GET /specific_method?method=GET (127.0.0.1) 0.78ms
--------------------- >> end captured logging << ---------------------
Andrey Petrov shazow commented on the diff
test/with_dummyserver/test_https.py
((6 lines not shown))
25 26
         self.assertEqual(r.status, 200, r.data)
26 27
 
  28
+    def test_set_ssl_version_to_tlsv1(self):
  29
+        self._pool.ssl_version = ssl.PROTOCOL_TLSv1
  30
+        r = self._pool.request('GET', '/specific_method',
  31
+            fields={'method': 'GET'})
  32
+        self.assertEqual(r.status, 200, r.data)
  33
+
  34
+    def test_set_ssl_version_to_sslv2(self):
  35
+        self._pool.ssl_version = ssl.PROTOCOL_SSLv2
  36
+        with self.assertRaises(SSLError):
1
Andrey Petrov Owner
shazow added a note

Why should this raise?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Ken Schwencke

@shazow So is this issue taken care of yet? :)

Andrey Petrov
Owner

@Schwanksta It has been merged into master. There might be minor changes before it's published, but it should be usable already.

Ken Schwencke

Awesome, I thought so, but I wasn't sure because the ticket was still open. Thanks @shazow !

Andrey Petrov shazow closed this
Thomas Weißschuh t-8ch referenced this pull request in kennethreitz/requests
Open

Disable SSL compression for security reasons. #1857

Kevin Burke

Might be missing something but I can't find these commits in urllib3 master...

Andrey Petrov
Owner

Bits and pieces are still there I think, but we've had several other ssl-related PRs which probably mutated much of the diff.

I think it's largely urllib3.util.resolve_ssl_version and such now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 4 unique commits by 1 author.

Oct 19, 2012
David Andrzejewski Added ability to choose SSL protocol version
This is the same as a change that I did for the requests project - which
required this urllib3 change - so I thought it might be appropriate to
contribute the change to the upstream library as well.
5557476
David Andrzejewski Added unit tests to cover my previous commit. 8166dbe
Oct 20, 2012
David Andrzejewski Fixes as requested by @shazow 80a1259
Oct 22, 2012
David Andrzejewski Added new ssl_version parameter to the docstring for HTTPSConnectionPool 2b6cfb3
This page is out of date. Refresh to see the latest.
15  test/with_dummyserver/test_https.py
... ...
@@ -1,4 +1,5 @@
1 1
 import logging
  2
+import ssl
2 3
 import sys
3 4
 import unittest
4 5
 
@@ -21,9 +22,21 @@ def setUp(self):
21 22
 
22 23
     def test_simple(self):
23 24
         r = self._pool.request('GET', '/specific_method',
24  
-                               fields={'method': 'GET'})
  25
+            fields={'method': 'GET'})
25 26
         self.assertEqual(r.status, 200, r.data)
26 27
 
  28
+    def test_set_ssl_version_to_tlsv1(self):
  29
+        self._pool.ssl_version = ssl.PROTOCOL_TLSv1
  30
+        r = self._pool.request('GET', '/specific_method',
  31
+            fields={'method': 'GET'})
  32
+        self.assertEqual(r.status, 200, r.data)
  33
+
  34
+    def test_set_ssl_version_to_sslv2(self):
  35
+        self._pool.ssl_version = ssl.PROTOCOL_SSLv2
  36
+        with self.assertRaises(SSLError):
  37
+            r = self._pool.request('GET', '/specific_method',
  38
+                                   fields={'method': 'GET'})
  39
+
27 40
     def test_verified(self):
28 41
         https_pool = HTTPSConnectionPool(self.host, self.port,
29 42
                                          cert_reqs='CERT_REQUIRED')
17  urllib3/connectionpool.py
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
76 76
     """
77 77
     cert_reqs = None
78 78
     ca_certs = None
  79
+    ssl_version = None
79 80
 
80 81
     def set_cert(self, key_file=None, cert_file=None,
81 82
                  cert_reqs='CERT_NONE', ca_certs=None):
@@ -98,7 +99,8 @@ def connect(self):
98 99
         # trusted_root_certs
99 100
         self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
100 101
                                     cert_reqs=self.cert_reqs,
101  
-                                    ca_certs=self.ca_certs)
  102
+                                    ca_certs=self.ca_certs,
  103
+                                    ssl_version=self.ssl_version)
102 104
         if self.ca_certs:
103 105
             match_hostname(self.sock.getpeercert(), self.host)
104 106
 
@@ -493,8 +495,8 @@ class HTTPSConnectionPool(HTTPConnectionPool):
493 495
     :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates,
494 496
     instead of :class:httplib.HTTPSConnection`.
495 497
 
496  
-    The ``key_file``, ``cert_file``, ``cert_reqs``, and ``ca_certs`` parameters
497  
-    are only used if :mod:`ssl` is available and are fed into
  498
+    The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, and ``ssl_version``
  499
+    parameters are only used if :mod:`ssl` is available and are fed into
498 500
     :meth:`ssl.wrap_socket` to upgrade the connection socket into an SSL socket.
499 501
     """
500 502
 
@@ -504,7 +506,7 @@ def __init__(self, host, port=None,
504 506
                  strict=False, timeout=None, maxsize=1,
505 507
                  block=False, headers=None,
506 508
                  key_file=None, cert_file=None,
507  
-                 cert_reqs='CERT_NONE', ca_certs=None):
  509
+                 cert_reqs='CERT_NONE', ca_certs=None, ssl_version=None):
508 510
 
509 511
         HTTPConnectionPool.__init__(self, host, port,
510 512
                                     strict, timeout, maxsize,
@@ -513,6 +515,7 @@ def __init__(self, host, port=None,
513 515
         self.cert_file = cert_file
514 516
         self.cert_reqs = cert_reqs
515 517
         self.ca_certs = ca_certs
  518
+        self.ssl_version = ssl_version
516 519
 
517 520
     def _new_conn(self):
518 521
         """
@@ -532,6 +535,12 @@ def _new_conn(self):
532 535
         connection = VerifiedHTTPSConnection(host=self.host, port=self.port)
533 536
         connection.set_cert(key_file=self.key_file, cert_file=self.cert_file,
534 537
                             cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
  538
+
  539
+        if self.ssl_version is None:
  540
+            connection.ssl_version = ssl.PROTOCOL_SSLv23
  541
+        else:
  542
+            connection.ssl_version = self.ssl_version
  543
+
535 544
         return connection
536 545
 
537 546
 
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.