Issue #19781: ftplib now supports SSLContext.check_hostname and server name

indication for TLS/SSL connections.
This commit is contained in:
Christian Heimes 2013-12-02 02:56:02 +01:00
parent 1aa9a75fbf
commit e5b5edfa2c
4 changed files with 51 additions and 3 deletions

View File

@ -94,6 +94,11 @@ The module defines the following items:
.. versionchanged:: 3.3 .. versionchanged:: 3.3
*source_address* parameter was added. *source_address* parameter was added.
.. versionchanged:: 3.4
The class now supports hostname check with
:attr:`SSLContext.check_hostname` and *Server Name Indicator* (see
:data:`~ssl.HAS_SNI`).
Here's a sample session using the :class:`FTP_TLS` class: Here's a sample session using the :class:`FTP_TLS` class:
>>> from ftplib import FTP_TLS >>> from ftplib import FTP_TLS
@ -427,6 +432,11 @@ FTP_TLS Objects
Set up secure control connection by using TLS or SSL, depending on what Set up secure control connection by using TLS or SSL, depending on what
specified in :meth:`ssl_version` attribute. specified in :meth:`ssl_version` attribute.
.. versionchanged:: 3.4
The method now supports hostname check with
:attr:`SSLContext.check_hostname` and *Server Name Indicator* (see
:data:`~ssl.HAS_SNI`).
.. method:: FTP_TLS.ccc() .. method:: FTP_TLS.ccc()
Revert control channel back to plaintext. This can be useful to take Revert control channel back to plaintext. This can be useful to take

View File

@ -748,7 +748,9 @@ else:
resp = self.voidcmd('AUTH TLS') resp = self.voidcmd('AUTH TLS')
else: else:
resp = self.voidcmd('AUTH SSL') resp = self.voidcmd('AUTH SSL')
self.sock = self.context.wrap_socket(self.sock) server_hostname = self.host if ssl.HAS_SNI else None
self.sock = self.context.wrap_socket(self.sock,
server_hostname=server_hostname)
self.file = self.sock.makefile(mode='r', encoding=self.encoding) self.file = self.sock.makefile(mode='r', encoding=self.encoding)
return resp return resp
@ -787,7 +789,9 @@ else:
def ntransfercmd(self, cmd, rest=None): def ntransfercmd(self, cmd, rest=None):
conn, size = FTP.ntransfercmd(self, cmd, rest) conn, size = FTP.ntransfercmd(self, cmd, rest)
if self._prot_p: if self._prot_p:
conn = self.context.wrap_socket(conn) server_hostname = self.host if ssl.HAS_SNI else None
conn = self.context.wrap_socket(conn,
server_hostname=server_hostname)
return conn, size return conn, size
def abort(self): def abort(self):

View File

@ -301,7 +301,8 @@ class DummyFTPServer(asyncore.dispatcher, threading.Thread):
if ssl is not None: if ssl is not None:
CERTFILE = os.path.join(os.path.dirname(__file__), "keycert.pem") CERTFILE = os.path.join(os.path.dirname(__file__), "keycert3.pem")
CAFILE = os.path.join(os.path.dirname(__file__), "pycacert.pem")
class SSLConnection(asyncore.dispatcher): class SSLConnection(asyncore.dispatcher):
"""An asyncore.dispatcher subclass supporting TLS/SSL.""" """An asyncore.dispatcher subclass supporting TLS/SSL."""
@ -923,6 +924,36 @@ class TestTLS_FTPClass(TestCase):
self.client.ccc() self.client.ccc()
self.assertRaises(ValueError, self.client.sock.unwrap) self.assertRaises(ValueError, self.client.sock.unwrap)
def test_check_hostname(self):
self.client.quit()
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.check_hostname = True
ctx.load_verify_locations(CAFILE)
self.client = ftplib.FTP_TLS(context=ctx, timeout=TIMEOUT)
# 127.0.0.1 doesn't match SAN
self.client.connect(self.server.host, self.server.port)
with self.assertRaises(ssl.CertificateError):
self.client.auth()
# exception quits connection
self.client.connect(self.server.host, self.server.port)
self.client.prot_p()
with self.assertRaises(ssl.CertificateError):
with self.client.transfercmd("list") as sock:
pass
self.client.quit()
self.client.connect("localhost", self.server.port)
self.client.auth()
self.client.quit()
self.client.connect("localhost", self.server.port)
self.client.prot_p()
with self.client.transfercmd("list") as sock:
pass
class TestTimeouts(TestCase): class TestTimeouts(TestCase):

View File

@ -18,6 +18,9 @@ Core and Builtins
Library Library
------- -------
- Issue #19781: ftplib now supports SSLContext.check_hostname and server name
indication for TLS/SSL connections.
- Issue #19509: Add SSLContext.check_hostname to match the peer's certificate - Issue #19509: Add SSLContext.check_hostname to match the peer's certificate
with server_hostname on handshake. with server_hostname on handshake.