(Merge 3.1) Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional

OpenSSL is now compiled with OPENSSL_NO_SSL2 defined (without the SSLv2
protocol) on Debian: fix the ssl module on Debian Testing and Debian Sid.

Optimize also ssl.get_protocol_name(): speed does matter!
This commit is contained in:
Victor Stinner 2011-05-10 00:48:41 +02:00
commit 17ca323e7c
5 changed files with 58 additions and 36 deletions

View File

@ -289,6 +289,9 @@ Constants
Selects SSL version 2 as the channel encryption protocol. Selects SSL version 2 as the channel encryption protocol.
This protocol is not available if OpenSSL is compiled with OPENSSL_NO_SSL2
flag.
.. warning:: .. warning::
SSL version 2 is insecure. Its use is highly discouraged. SSL version 2 is insecure. Its use is highly discouraged.

View File

@ -62,8 +62,6 @@ import _ssl # if we can't import it, let the error propagate
from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
from _ssl import _SSLContext, SSLError from _ssl import _SSLContext, SSLError
from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED from _ssl import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
from _ssl import (PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23,
PROTOCOL_TLSv1)
from _ssl import OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 from _ssl import OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1
from _ssl import RAND_status, RAND_egd, RAND_add from _ssl import RAND_status, RAND_egd, RAND_add
from _ssl import ( from _ssl import (
@ -78,6 +76,18 @@ from _ssl import (
SSL_ERROR_INVALID_ERROR_CODE, SSL_ERROR_INVALID_ERROR_CODE,
) )
from _ssl import HAS_SNI from _ssl import HAS_SNI
from _ssl import PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1
_PROTOCOL_NAMES = {
PROTOCOL_TLSv1: "TLSv1",
PROTOCOL_SSLv23: "SSLv23",
PROTOCOL_SSLv3: "SSLv3",
}
try:
from _ssl import PROTOCOL_SSLv2
except ImportError:
pass
else:
_PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2"
from socket import getnameinfo as _getnameinfo from socket import getnameinfo as _getnameinfo
from socket import error as socket_error from socket import error as socket_error
@ -552,13 +562,4 @@ def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None):
return DER_cert_to_PEM_cert(dercert) return DER_cert_to_PEM_cert(dercert)
def get_protocol_name(protocol_code): def get_protocol_name(protocol_code):
if protocol_code == PROTOCOL_TLSv1: return _PROTOCOL_NAMES.get(protocol_code, '<unknown>')
return "TLSv1"
elif protocol_code == PROTOCOL_SSLv23:
return "SSLv23"
elif protocol_code == PROTOCOL_SSLv2:
return "SSLv2"
elif protocol_code == PROTOCOL_SSLv3:
return "SSLv3"
else:
return "<unknown>"

View File

@ -21,9 +21,11 @@ import functools
ssl = support.import_module("ssl") ssl = support.import_module("ssl")
PROTOCOLS = [ PROTOCOLS = [
ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3,
ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1 ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1
] ]
if hasattr(ssl, 'PROTOCOL_SSLv2'):
PROTOCOLS.append(ssl.PROTOCOL_SSLv2)
HOST = support.HOST HOST = support.HOST
@ -67,22 +69,25 @@ def no_sslv2_implies_sslv3_hello():
# Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2 # Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2
def skip_if_broken_ubuntu_ssl(func): def skip_if_broken_ubuntu_ssl(func):
@functools.wraps(func) if hasattr(ssl, 'PROTOCOL_SSLv2'):
def f(*args, **kwargs): @functools.wraps(func)
try: def f(*args, **kwargs):
ssl.SSLContext(ssl.PROTOCOL_SSLv2) try:
except ssl.SSLError: ssl.SSLContext(ssl.PROTOCOL_SSLv2)
if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and except ssl.SSLError:
platform.linux_distribution() == ('debian', 'squeeze/sid', '')): if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and
raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour") platform.linux_distribution() == ('debian', 'squeeze/sid', '')):
return func(*args, **kwargs) raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour")
return f return func(*args, **kwargs)
return f
else:
return func
class BasicSocketTests(unittest.TestCase): class BasicSocketTests(unittest.TestCase):
def test_constants(self): def test_constants(self):
ssl.PROTOCOL_SSLv2 #ssl.PROTOCOL_SSLv2
ssl.PROTOCOL_SSLv23 ssl.PROTOCOL_SSLv23
ssl.PROTOCOL_SSLv3 ssl.PROTOCOL_SSLv3
ssl.PROTOCOL_TLSv1 ssl.PROTOCOL_TLSv1
@ -310,7 +315,8 @@ class ContextTests(unittest.TestCase):
@skip_if_broken_ubuntu_ssl @skip_if_broken_ubuntu_ssl
def test_constructor(self): def test_constructor(self):
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2) if hasattr(ssl, 'PROTOCOL_SSLv2'):
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2)
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv3) ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv3)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
@ -1199,6 +1205,7 @@ else:
t.join() t.join()
@skip_if_broken_ubuntu_ssl @skip_if_broken_ubuntu_ssl
@unittest.skipUnless(hasattr(ssl, 'PROTOCOL_SSLv2'), "need SSLv2")
def test_protocol_sslv2(self): def test_protocol_sslv2(self):
"""Connecting to an SSLv2 server with various client options""" """Connecting to an SSLv2 server with various client options"""
if support.verbose: if support.verbose:
@ -1224,14 +1231,15 @@ else:
"""Connecting to an SSLv23 server with various client options""" """Connecting to an SSLv23 server with various client options"""
if support.verbose: if support.verbose:
sys.stdout.write("\n") sys.stdout.write("\n")
try: if hasattr(ssl, 'PROTOCOL_SSLv2'):
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True) try:
except (ssl.SSLError, socket.error) as x: try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
# this fails on some older versions of OpenSSL (0.9.7l, for instance) except (ssl.SSLError, socket.error) as x:
if support.verbose: # this fails on some older versions of OpenSSL (0.9.7l, for instance)
sys.stdout.write( if support.verbose:
" SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" sys.stdout.write(
% str(x)) " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
% str(x))
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
@ -1262,7 +1270,8 @@ else:
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) if hasattr(ssl, 'PROTOCOL_SSLv2'):
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
if no_sslv2_implies_sslv3_hello(): if no_sslv2_implies_sslv3_hello():
@ -1278,7 +1287,8 @@ else:
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) if hasattr(ssl, 'PROTOCOL_SSLv2'):
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False) try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)

View File

@ -618,6 +618,8 @@ Core and Builtins
Library Library
------- -------
- Issue #12012: ssl.PROTOCOL_SSLv2 becomes optional.
- Issue #10916: mmap should not segfault when a file is mapped using 0 as length - Issue #10916: mmap should not segfault when a file is mapped using 0 as length
and a non-zero offset, and an attempt to read past the end of file is made and a non-zero offset, and an attempt to read past the end of file is made
(IndexError is raised instead). Patch by Ross Lagerwall. (IndexError is raised instead). Patch by Ross Lagerwall.

View File

@ -63,8 +63,10 @@ enum py_ssl_cert_requirements {
}; };
enum py_ssl_version { enum py_ssl_version {
#ifndef OPENSSL_NO_SSL2
PY_SSL_VERSION_SSL2, PY_SSL_VERSION_SSL2,
PY_SSL_VERSION_SSL3, #endif
PY_SSL_VERSION_SSL3=1,
PY_SSL_VERSION_SSL23, PY_SSL_VERSION_SSL23,
PY_SSL_VERSION_TLS1 PY_SSL_VERSION_TLS1
}; };
@ -1450,8 +1452,10 @@ context_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
ctx = SSL_CTX_new(TLSv1_method()); ctx = SSL_CTX_new(TLSv1_method());
else if (proto_version == PY_SSL_VERSION_SSL3) else if (proto_version == PY_SSL_VERSION_SSL3)
ctx = SSL_CTX_new(SSLv3_method()); ctx = SSL_CTX_new(SSLv3_method());
#ifndef OPENSSL_NO_SSL2
else if (proto_version == PY_SSL_VERSION_SSL2) else if (proto_version == PY_SSL_VERSION_SSL2)
ctx = SSL_CTX_new(SSLv2_method()); ctx = SSL_CTX_new(SSLv2_method());
#endif
else if (proto_version == PY_SSL_VERSION_SSL23) else if (proto_version == PY_SSL_VERSION_SSL23)
ctx = SSL_CTX_new(SSLv23_method()); ctx = SSL_CTX_new(SSLv23_method());
else else
@ -2110,8 +2114,10 @@ PyInit__ssl(void)
PY_SSL_CERT_REQUIRED); PY_SSL_CERT_REQUIRED);
/* protocol versions */ /* protocol versions */
#ifndef OPENSSL_NO_SSL2
PyModule_AddIntConstant(m, "PROTOCOL_SSLv2", PyModule_AddIntConstant(m, "PROTOCOL_SSLv2",
PY_SSL_VERSION_SSL2); PY_SSL_VERSION_SSL2);
#endif
PyModule_AddIntConstant(m, "PROTOCOL_SSLv3", PyModule_AddIntConstant(m, "PROTOCOL_SSLv3",
PY_SSL_VERSION_SSL3); PY_SSL_VERSION_SSL3);
PyModule_AddIntConstant(m, "PROTOCOL_SSLv23", PyModule_AddIntConstant(m, "PROTOCOL_SSLv23",