From: Christian Heimes Date: Mon, 5 Sep 2016 21:23:24 +0000 (+0200) Subject: Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=01113faef983fc5c495fbacc00bbb55eab02dfc3;p=python Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0. --- 01113faef983fc5c495fbacc00bbb55eab02dfc3 diff --cc Doc/library/ssl.rst index 5792d0d407,d8fc8de115..04fad06a64 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@@ -49,6 -49,6 +49,12 @@@ For more sophisticated applications, th helps manage settings and certificates, which can then be inherited by SSL sockets created through the :meth:`SSLContext.wrap_socket` method. ++.. versionchanged:: 3.6 ++ ++ OpenSSL 0.9.8, 1.0.0 and 1.0.1 are deprecated and no longer supported. ++ In the future the ssl module will require at least OpenSSL 1.0.2 or ++ 1.1.0. ++ Functions, Constants, and Exceptions ------------------------------------ @@@ -316,6 -316,11 +322,11 @@@ Random generatio .. versionadded:: 3.3 - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + OpenSSL has deprecated :func:`ssl.RAND_pseudo_bytes`, use + :func:`ssl.RAND_bytes` instead. + .. function:: RAND_status() Return ``True`` if the SSL pseudo-random number generator has been seeded @@@ -573,6 -581,16 +587,16 @@@ Constant Selects the highest protocol version that both the client and server support. Despite the name, this option can select "TLS" protocols as well as "SSL". - .. versionadded:: 3.5.3 ++ .. versionadded:: 3.6 + + .. data:: PROTOCOL_SSLv23 + + Alias for data:`PROTOCOL_TLS`. + - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + Use data:`PROTOCOL_TLS` instead. + .. data:: PROTOCOL_SSLv2 Selects SSL version 2 as the channel encryption protocol. @@@ -584,6 -602,10 +608,10 @@@ SSL version 2 is insecure. Its use is highly discouraged. - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + OpenSSL has removed support for SSLv2. + .. data:: PROTOCOL_SSLv3 Selects SSL version 3 as the channel encryption protocol. @@@ -595,10 -617,20 +623,20 @@@ SSL version 3 is insecure. Its use is highly discouraged. - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + OpenSSL has deprecated all version specific protocols. Use the default + protocol data:`PROTOCOL_TLS` with flags like data:`OP_NO_SSLv3` instead. + .. data:: PROTOCOL_TLSv1 Selects TLS version 1.0 as the channel encryption protocol. - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + OpenSSL has deprecated all version specific protocols. Use the default + protocol data:`PROTOCOL_TLS` with flags like data:`OP_NO_SSLv3` instead. + .. data:: PROTOCOL_TLSv1_1 Selects TLS version 1.1 as the channel encryption protocol. @@@ -606,6 -638,11 +644,11 @@@ .. versionadded:: 3.4 - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + OpenSSL has deprecated all version specific protocols. Use the default + protocol data:`PROTOCOL_TLS` with flags like data:`OP_NO_SSLv3` instead. + .. data:: PROTOCOL_TLSv1_2 Selects TLS version 1.2 as the channel encryption protocol. This is the @@@ -614,6 -651,11 +657,11 @@@ .. versionadded:: 3.4 - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + OpenSSL has deprecated all version specific protocols. Use the default + protocol data:`PROTOCOL_TLS` with flags like data:`OP_NO_SSLv3` instead. + .. data:: OP_ALL Enables workarounds for various bugs present in other SSL implementations. @@@ -630,6 -672,11 +678,11 @@@ .. versionadded:: 3.2 - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + SSLv2 is deprecated + + .. data:: OP_NO_SSLv3 Prevents an SSLv3 connection. This option is only applicable in @@@ -638,6 -685,10 +691,10 @@@ .. versionadded:: 3.2 - .. deprecated:: 3.5.3 ++ .. deprecated:: 3.6 + + SSLv3 is deprecated + .. data:: OP_NO_TLSv1 Prevents a TLSv1 connection. This option is only applicable in @@@ -1092,6 -1143,10 +1149,10 @@@ to speed up repeated connections from t :func:`create_default_context` lets the :mod:`ssl` module choose security settings for a given purpose. - .. versionchanged:: 3.5.3 ++ .. versionchanged:: 3.6 + + :data:`PROTOCOL_TLS` is the default value. + :class:`SSLContext` objects have the following methods and attributes: diff --cc Lib/test/test_ssl.py index 6cd5454ab4,79e26ba45b..f6afa267c5 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@@ -21,15 -21,11 +21,18 @@@ import functool ssl = support.import_module("ssl") +try: + import threading +except ImportError: + _have_threads = False +else: + _have_threads = True + PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) HOST = support.HOST + IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL') + IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0) + def data_file(*name): return os.path.join(os.path.dirname(__file__), *name) @@@ -1655,128 -1742,64 +1660,128 @@@ class SimpleBackgroundTests(unittest.Te % (count, func.__name__)) return ret - def test_handshake(self): + def test_bio_handshake(self): + sock = socket.socket(socket.AF_INET) + self.addCleanup(sock.close) + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.load_verify_locations(SIGNING_CA) + ctx.check_hostname = True + sslobj = ctx.wrap_bio(incoming, outgoing, False, 'localhost') + self.assertIs(sslobj._sslobj.owner, sslobj) + self.assertIsNone(sslobj.cipher()) - self.assertIsNone(sslobj.shared_ciphers()) ++ self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertRaises(ValueError, sslobj.getpeercert) + if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: + self.assertIsNone(sslobj.get_channel_binding('tls-unique')) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + self.assertTrue(sslobj.cipher()) - self.assertIsNone(sslobj.shared_ciphers()) ++ self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertTrue(sslobj.getpeercert()) + if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: + self.assertTrue(sslobj.get_channel_binding('tls-unique')) + try: + self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + except ssl.SSLSyscallError: + # If the server shuts down the TCP connection without sending a + # secure shutdown message, this is reported as SSL_ERROR_SYSCALL + pass + self.assertRaises(ssl.SSLError, sslobj.write, b'foo') + + def test_bio_read_write_data(self): + sock = socket.socket(socket.AF_INET) + self.addCleanup(sock.close) + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ctx.verify_mode = ssl.CERT_NONE + sslobj = ctx.wrap_bio(incoming, outgoing, False) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + req = b'FOO\n' + self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req) + buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024) + self.assertEqual(buf, b'foo\n') + self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + + +class NetworkedTests(unittest.TestCase): + + def test_timeout_connect_ex(self): + # Issue #12065: on a timeout, connect_ex() should return the original + # errno (mimicking the behaviour of non-SSL sockets). with support.transient_internet(REMOTE_HOST): - sock = socket.socket(socket.AF_INET) - sock.connect((REMOTE_HOST, 443)) - incoming = ssl.MemoryBIO() - outgoing = ssl.MemoryBIO() - ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + do_handshake_on_connect=False) + self.addCleanup(s.close) + s.settimeout(0.0000001) + rc = s.connect_ex((REMOTE_HOST, 443)) + if rc == 0: + self.skipTest("REMOTE_HOST responded too quickly") + self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK)) + + @unittest.skipUnless(support.IPV6_ENABLED, 'Needs IPv6') + def test_get_server_certificate_ipv6(self): + with support.transient_internet('ipv6.google.com'): + _test_get_server_certificate(self, 'ipv6.google.com', 443) + _test_get_server_certificate_fail(self, 'ipv6.google.com', 443) + + def test_algorithms(self): + # Issue #8484: all algorithms should be available when verifying a + # certificate. + # SHA256 was added in OpenSSL 0.9.8 + if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): + self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) + # sha256.tbs-internet.com needs SNI to use the correct certificate + if not ssl.HAS_SNI: + self.skipTest("SNI needed for this test") + # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host) + remote = ("sha256.tbs-internet.com", 443) + sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") + with support.transient_internet("sha256.tbs-internet.com"): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.verify_mode = ssl.CERT_REQUIRED - ctx.load_verify_locations(REMOTE_ROOT_CERT) - ctx.check_hostname = True - sslobj = ctx.wrap_bio(incoming, outgoing, False, REMOTE_HOST) - self.assertIs(sslobj._sslobj.owner, sslobj) - self.assertIsNone(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) - self.assertRaises(ValueError, sslobj.getpeercert) - if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: - self.assertIsNone(sslobj.get_channel_binding('tls-unique')) - self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) - self.assertTrue(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) - self.assertTrue(sslobj.getpeercert()) - if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: - self.assertTrue(sslobj.get_channel_binding('tls-unique')) + ctx.load_verify_locations(sha256_cert) + s = ctx.wrap_socket(socket.socket(socket.AF_INET), + server_hostname="sha256.tbs-internet.com") try: - self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) - except ssl.SSLSyscallError: - # self-signed.pythontest.net probably shuts down the TCP - # connection without sending a secure shutdown message, and - # this is reported as SSL_ERROR_SYSCALL - pass - self.assertRaises(ssl.SSLError, sslobj.write, b'foo') - sock.close() + s.connect(remote) + if support.verbose: + sys.stdout.write("\nCipher with %r is %r\n" % + (remote, s.cipher())) + sys.stdout.write("Certificate is:\n%s\n" % + pprint.pformat(s.getpeercert())) + finally: + s.close() - def test_read_write_data(self): - with support.transient_internet(REMOTE_HOST): - sock = socket.socket(socket.AF_INET) - sock.connect((REMOTE_HOST, 443)) - incoming = ssl.MemoryBIO() - outgoing = ssl.MemoryBIO() - ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - ctx.verify_mode = ssl.CERT_NONE - sslobj = ctx.wrap_bio(incoming, outgoing, False) - self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) - req = b'GET / HTTP/1.0\r\n\r\n' - self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req) - buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024) - self.assertEqual(buf[:5], b'HTTP/') - self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) - sock.close() +def _test_get_server_certificate(test, host, port, cert=None): + pem = ssl.get_server_certificate((host, port)) + if not pem: + test.fail("No server certificate on %s:%s!" % (host, port)) -try: - import threading -except ImportError: - _have_threads = False -else: - _have_threads = True + pem = ssl.get_server_certificate((host, port), ca_certs=cert) + if not pem: + test.fail("No server certificate on %s:%s!" % (host, port)) + if support.verbose: + sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem)) +def _test_get_server_certificate_fail(test, host, port): + try: + pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE) + except ssl.SSLError as x: + #should fail + if support.verbose: + sys.stdout.write("%s\n" % x) + else: + test.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) + + +if _have_threads: from test.ssl_servers import make_https_server class ThreadedEchoServer(threading.Thread): diff --cc Misc/NEWS index 5fdabe0359,49b1ce2179..428cf2fd9e --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -72,24 -36,31 +72,26 @@@ Core and Builtin In a brand new thread, raise a RuntimeError since there is no active exception to reraise. Patch written by Xiang Zhang. -- Issue #27419: Standard __import__() no longer look up "__import__" in globals - or builtins for importing submodules or "from import". Fixed handling an - error of non-string package name. - -- Issue #27083: Respect the PYTHONCASEOK environment variable under Windows. - -- Issue #27514: Make having too many statically nested blocks a SyntaxError - instead of SystemError. +Library +------- -- Issue #27473: Fixed possible integer overflow in bytes and bytearray - concatenations. Patch by Xiang Zhang. ++- Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0. + -- Issue #27507: Add integer overflow check in bytearray.extend(). Patch by - Xiang Zhang. +- Issue #11620: Fix support for SND_MEMORY in winsound.PlaySound. Based on a + patch by Tim Lesher. -- Issue #27581: Don't rely on wrapping for overflow check in - PySequence_Tuple(). Patch by Xiang Zhang. +- Issue #11734: Add support for IEEE 754 half-precision floats to the + struct module. Based on a patch by Eli Stevens. -- Issue #27443: __length_hint__() of bytearray iterators no longer return a - negative integer for a resized bytearray. +- Issue #27919: Deprecated ``extra_path`` distribution option in distutils + packaging. -Library -------- +- Issue #23229: Add new ``cmath`` constants: ``cmath.inf`` and ``cmath.nan`` to + match ``math.inf`` and ``math.nan``, and also ``cmath.infj`` and + ``cmath.nanj`` to match the format used by complex repr. -- Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0. +- Issue #27842: The csv.DictReader now returns rows of type OrderedDict. + (Contributed by Steve Holden.) - Issue #12885: Fix error when distutils encounters symlink.