diff -r 29d67ac7a9d5 Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py Tue Dec 03 02:05:42 2013 +0100 +++ b/Lib/asyncio/selector_events.py Wed Dec 04 08:12:29 2013 +0100 @@ -583,7 +583,8 @@ # cadefault=True. if hasattr(ssl, '_create_stdlib_context'): sslcontext = ssl._create_stdlib_context( - cert_reqs=ssl.CERT_REQUIRED) + cert_reqs=ssl.CERT_REQUIRED, + check_hostname=True) else: # Fallback for Python 3.3. sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) @@ -639,17 +640,19 @@ self._loop.remove_reader(self._sock_fd) self._loop.remove_writer(self._sock_fd) - # Verify hostname if requested. peercert = self._sock.getpeercert() - if (self._server_hostname and - self._sslcontext.verify_mode != ssl.CERT_NONE): - try: - ssl.match_hostname(peercert, self._server_hostname) - except Exception as exc: - self._sock.close() - if self._waiter is not None: - self._waiter.set_exception(exc) - return + 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): + try: + ssl.match_hostname(peercert, self._server_hostname) + except Exception as exc: + self._sock.close() + if self._waiter is not None: + self._waiter.set_exception(exc) + return # Add extra info that becomes available after handshake. self._extra.update(peercert=peercert, diff -r 29d67ac7a9d5 Lib/test/test_asyncio/test_events.py --- a/Lib/test/test_asyncio/test_events.py Tue Dec 03 02:05:42 2013 +0100 +++ b/Lib/test/test_asyncio/test_events.py Wed Dec 04 08:12:29 2013 +0100 @@ -646,6 +646,63 @@ # stop serving server.close() + @unittest.skipIf(ssl is None, 'No ssl module') + def test_create_server_ssl_verified(self): + proto = None + + def factory(): + nonlocal proto + proto = MyProto(loop=self.loop) + return proto + + here = os.path.dirname(__file__) + sslcontext_srv = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + sslcontext_srv.options |= ssl.OP_NO_SSLv2 + sslcontext_srv.load_cert_chain( + certfile=os.path.join(here, '..', 'keycert3.pem')) + + f = self.loop.create_server( + factory, '127.0.0.1', 0, ssl=sslcontext_srv) + + server = self.loop.run_until_complete(f) + sock = server.sockets[0] + host, port = sock.getsockname() + self.assertEqual(host, '127.0.0.1') + + sslcontext_client = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + sslcontext_client.options |= ssl.OP_NO_SSLv2 + sslcontext_client.verify_mode = ssl.CERT_REQUIRED + if sys.version_info >= (3, 4): + sslcontext_client.check_hostname = True + + # no CA loaded + f_c = self.loop.create_connection(MyProto, host, port, + ssl=sslcontext_client) + with self.assertRaisesRegex(ssl.SSLError, + "certificate verify failed "): + self.loop.run_until_complete(f_c) + + sslcontext_client.load_verify_locations( + cafile=os.path.join(here, '..', 'pycacert.pem')) + + # incorrect server_hostname + f_c = self.loop.create_connection(MyProto, host, port, + ssl=sslcontext_client) + with self.assertRaisesRegex(ssl.CertificateError, + "hostname '127.0.0.1' doesn't match 'localhost'"): + self.loop.run_until_complete(f_c) + + # Connection succeeds with correct CA and server hostname. + f_c = self.loop.create_connection(MyProto, host, port, + ssl=sslcontext_client, + server_hostname="localhost") + client, pr = self.loop.run_until_complete(f_c) + + # close connection + proto.transport.close() + client.close() + server.close() + def test_create_server_sock(self): proto = futures.Future(loop=self.loop)