summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/asyncio/sslproto.py6
-rw-r--r--Lib/http/client.py10
-rw-r--r--Lib/ssl.py29
-rw-r--r--Lib/test/test_asyncio/test_events.py6
-rw-r--r--Lib/test/test_ftplib.py3
-rw-r--r--Lib/test/test_imaplib.py6
-rw-r--r--Lib/test/test_poplib.py3
-rw-r--r--Lib/test/test_ssl.py28
-rw-r--r--Lib/test/test_urllib2_localnet.py2
9 files changed, 63 insertions, 30 deletions
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index 2d377c4..1130bce 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -590,12 +590,6 @@ class SSLProtocol(protocols.Protocol):
raise handshake_exc
peercert = sslobj.getpeercert()
- if not hasattr(self._sslcontext, 'check_hostname'):
- # Verify hostname if requested, Python 3.4+ uses check_hostname
- # and checks the hostname in do_handshake()
- if (self._server_hostname and
- self._sslcontext.verify_mode != ssl.CERT_NONE):
- ssl.match_hostname(peercert, self._server_hostname)
except BaseException as exc:
if self._loop.get_debug():
if isinstance(exc, ssl.CertificateError):
diff --git a/Lib/http/client.py b/Lib/http/client.py
index 1a852cd..1292db7 100644
--- a/Lib/http/client.py
+++ b/Lib/http/client.py
@@ -1375,7 +1375,8 @@ else:
if key_file or cert_file:
context.load_cert_chain(cert_file, key_file)
self._context = context
- self._check_hostname = check_hostname
+ if check_hostname is not None:
+ self._context.check_hostname = check_hostname
def connect(self):
"Connect to a host on a given (SSL) port."
@@ -1389,13 +1390,6 @@ else:
self.sock = self._context.wrap_socket(self.sock,
server_hostname=server_hostname)
- if not self._context.check_hostname and self._check_hostname:
- try:
- ssl.match_hostname(self.sock.getpeercert(), server_hostname)
- except Exception:
- self.sock.shutdown(socket.SHUT_RDWR)
- self.sock.close()
- raise
__all__.append("HTTPSConnection")
diff --git a/Lib/ssl.py b/Lib/ssl.py
index 7c4cccf..5f972e1 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -148,7 +148,6 @@ _IntEnum._convert(
lambda name: name.startswith('CERT_'),
source=_ssl)
-
PROTOCOL_SSLv23 = _SSLMethod.PROTOCOL_SSLv23 = _SSLMethod.PROTOCOL_TLS
_PROTOCOL_NAMES = {value: name for name, value in _SSLMethod.__members__.items()}
@@ -172,6 +171,8 @@ if _ssl.HAS_TLS_UNIQUE:
else:
CHANNEL_BINDING_TYPES = []
+HAS_NEVER_CHECK_COMMON_NAME = hasattr(_ssl, 'HOSTFLAG_NEVER_CHECK_SUBJECT')
+
# Disable weak or insecure ciphers by default
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
@@ -216,9 +217,7 @@ _RESTRICTED_SERVER_CIPHERS = (
'!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES'
)
-
-class CertificateError(ValueError):
- pass
+CertificateError = SSLCertVerificationError
def _dnsname_match(dn, hostname):
@@ -473,6 +472,23 @@ class SSLContext(_SSLContext):
def options(self, value):
super(SSLContext, SSLContext).options.__set__(self, value)
+ if hasattr(_ssl, 'HOSTFLAG_NEVER_CHECK_SUBJECT'):
+ @property
+ def hostname_checks_common_name(self):
+ ncs = self._host_flags & _ssl.HOSTFLAG_NEVER_CHECK_SUBJECT
+ return ncs != _ssl.HOSTFLAG_NEVER_CHECK_SUBJECT
+
+ @hostname_checks_common_name.setter
+ def hostname_checks_common_name(self, value):
+ if value:
+ self._host_flags &= ~_ssl.HOSTFLAG_NEVER_CHECK_SUBJECT
+ else:
+ self._host_flags |= _ssl.HOSTFLAG_NEVER_CHECK_SUBJECT
+ else:
+ @property
+ def hostname_checks_common_name(self):
+ return True
+
@property
def verify_flags(self):
return VerifyFlags(super().verify_flags)
@@ -699,11 +715,6 @@ class SSLObject:
def do_handshake(self):
"""Start the SSL/TLS handshake."""
self._sslobj.do_handshake()
- if self.context.check_hostname:
- if not self.server_hostname:
- raise ValueError("check_hostname needs server_hostname "
- "argument")
- match_hostname(self.getpeercert(), self.server_hostname)
def unwrap(self):
"""Start the SSL shutdown handshake."""
diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
index e4b0536..cf21753 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -1148,11 +1148,13 @@ class EventLoopTestsMixin:
with test_utils.disable_logger():
with self.assertRaisesRegex(
ssl.CertificateError,
- "hostname '127.0.0.1' doesn't match 'localhost'"):
+ "IP address mismatch, certificate is not valid for "
+ "'127.0.0.1'"):
self.loop.run_until_complete(f_c)
# close connection
- proto.transport.close()
+ # transport is None because TLS ALERT aborted the handshake
+ self.assertIsNone(proto.transport)
server.close()
@support.skip_unless_bind_unix_socket
diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
index f1b0185..bb5a67f 100644
--- a/Lib/test/test_ftplib.py
+++ b/Lib/test/test_ftplib.py
@@ -330,6 +330,9 @@ if ssl is not None:
return
elif err.args[0] == ssl.SSL_ERROR_EOF:
return self.handle_close()
+ # TODO: SSLError does not expose alert information
+ elif "SSLV3_ALERT_BAD_CERTIFICATE" in err.args[1]:
+ return self.handle_close()
raise
except OSError as err:
if err.args[0] == errno.ECONNABORTED:
diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
index 4a45be6..f16bacd 100644
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -485,7 +485,8 @@ class NewIMAPSSLTests(NewIMAPTestsMixin, unittest.TestCase):
ssl_context.load_verify_locations(CAFILE)
with self.assertRaisesRegex(ssl.CertificateError,
- "hostname '127.0.0.1' doesn't match 'localhost'"):
+ "IP address mismatch, certificate is not valid for "
+ "'127.0.0.1'"):
_, server = self._setup(SimpleIMAPHandler)
client = self.imap_class(*server.server_address,
ssl_context=ssl_context)
@@ -874,7 +875,8 @@ class ThreadedNetworkedTestsSSL(ThreadedNetworkedTests):
with self.assertRaisesRegex(
ssl.CertificateError,
- "hostname '127.0.0.1' doesn't match 'localhost'"):
+ "IP address mismatch, certificate is not valid for "
+ "'127.0.0.1'"):
with self.reaped_server(SimpleIMAPHandler) as server:
client = self.imap_class(*server.server_address,
ssl_context=ssl_context)
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
index 9ba678f..4d7a439 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -176,6 +176,9 @@ class DummyPOP3Handler(asynchat.async_chat):
return
elif err.args[0] == ssl.SSL_ERROR_EOF:
return self.handle_close()
+ # TODO: SSLError does not expose alert information
+ elif "SSLV3_ALERT_BAD_CERTIFICATE" in err.args[1]:
+ return self.handle_close()
raise
except OSError as err:
if err.args[0] == errno.ECONNABORTED:
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index e3fa423..fdf727f 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -988,6 +988,19 @@ class ContextTests(unittest.TestCase):
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
self.assertTrue(ctx.check_hostname)
+ def test_hostname_checks_common_name(self):
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+ self.assertTrue(ctx.hostname_checks_common_name)
+ if ssl.HAS_NEVER_CHECK_COMMON_NAME:
+ ctx.hostname_checks_common_name = True
+ self.assertTrue(ctx.hostname_checks_common_name)
+ ctx.hostname_checks_common_name = False
+ self.assertFalse(ctx.hostname_checks_common_name)
+ ctx.hostname_checks_common_name = True
+ self.assertTrue(ctx.hostname_checks_common_name)
+ else:
+ with self.assertRaises(AttributeError):
+ ctx.hostname_checks_common_name = True
@unittest.skipUnless(have_verify_flags(),
"verify_flags need OpenSSL > 0.9.8")
@@ -1511,6 +1524,16 @@ class SSLErrorTests(unittest.TestCase):
ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
server_hostname="xn--.com")
+ def test_bad_server_hostname(self):
+ ctx = ssl.create_default_context()
+ with self.assertRaises(ValueError):
+ ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
+ server_hostname="")
+ with self.assertRaises(ValueError):
+ ctx.wrap_bio(ssl.MemoryBIO(), ssl.MemoryBIO(),
+ server_hostname=".example.org")
+
+
class MemoryBIOTests(unittest.TestCase):
def test_read_write(self):
@@ -2536,8 +2559,9 @@ class ThreadedTests(unittest.TestCase):
with server:
with client_context.wrap_socket(socket.socket(),
server_hostname="invalid") as s:
- with self.assertRaisesRegex(ssl.CertificateError,
- "hostname 'invalid' doesn't match 'localhost'"):
+ with self.assertRaisesRegex(
+ ssl.CertificateError,
+ "Hostname mismatch, certificate is not valid for 'invalid'."):
s.connect((HOST, server.port))
# missing server_hostname arg should cause an exception, too
diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py
index b2d1e5f..52c897a 100644
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -573,7 +573,7 @@ class TestUrlopen(unittest.TestCase):
cafile=CERT_fakehostname)
# Good cert, but mismatching hostname
handler = self.start_https_server(certfile=CERT_fakehostname)
- with self.assertRaises(ssl.CertificateError) as cm:
+ with self.assertRaises(urllib.error.URLError) as cm:
self.urlopen("https://localhost:%s/bizarre" % handler.port,
cafile=CERT_fakehostname)