Skip to content

Commit

Permalink
Bring back SSL option validation on startup by introducing handlers.v…
Browse files Browse the repository at this point in the history
…alidate_ssl_options
  • Loading branch information
zuohaocheng committed Jul 17, 2017
1 parent 3ab8723 commit 5737721
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 24 deletions.
44 changes: 25 additions & 19 deletions pyftpdlib/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3469,17 +3469,7 @@ def verify_certs_callback(self, connection, x509,

def get_ssl_context(self):
if self.ssl_context is None:
if self.certfile is None:
raise ValueError("at least certfile must be specified")
self.ssl_context = SSL.Context(self.ssl_protocol)
if self.ssl_protocol != SSL.SSLv2_METHOD:
self.ssl_context.set_options(SSL.OP_NO_SSLv2)
else:
warnings.warn("SSLv2 protocol is insecure", RuntimeWarning)
self.ssl_context.use_certificate_chain_file(self.certfile)
if not self.keyfile:
self.keyfile = self.certfile
self.ssl_context.use_privatekey_file(self.keyfile)
self.ssl_context = self.validate_ssl_options()
if self.client_certfile is not None:
from OpenSSL.SSL import VERIFY_CLIENT_ONCE
from OpenSSL.SSL import VERIFY_FAIL_IF_NO_PEER_CERT
Expand All @@ -3488,16 +3478,32 @@ def get_ssl_context(self):
VERIFY_FAIL_IF_NO_PEER_CERT |
VERIFY_CLIENT_ONCE,
self.verify_certs_callback)
from OpenSSL.SSL import OP_NO_TICKET
from OpenSSL.SSL import SESS_CACHE_OFF
self.ssl_context.load_verify_locations(
self.client_certfile)
self.ssl_context.set_session_cache_mode(SESS_CACHE_OFF)
self.ssl_options = self.ssl_options | OP_NO_TICKET
if self.ssl_options:
self.ssl_context.set_options(self.ssl_options)
return self.ssl_context

@classmethod
def validate_ssl_options(cls):
if cls.certfile is None:
raise ValueError("at least certfile must be specified")
ssl_context = SSL.Context(cls.ssl_protocol)
if cls.ssl_protocol != SSL.SSLv2_METHOD:
ssl_context.set_options(SSL.OP_NO_SSLv2)
else:
warnings.warn("SSLv2 protocol is insecure", RuntimeWarning)
ssl_context.use_certificate_chain_file(cls.certfile)
if not cls.keyfile:
cls.keyfile = cls.certfile
ssl_context.use_privatekey_file(cls.keyfile)
if cls.client_certfile is not None:
from OpenSSL.SSL import OP_NO_TICKET
from OpenSSL.SSL import SESS_CACHE_OFF
ssl_context.load_verify_locations(
cls.client_certfile)
ssl_context.set_session_cache_mode(SESS_CACHE_OFF)
cls.ssl_options = cls.ssl_options | OP_NO_TICKET
if cls.ssl_options:
ssl_context.set_options(cls.ssl_options)
return ssl_context

# --- overridden methods

def flush_account(self):
Expand Down
4 changes: 2 additions & 2 deletions pyftpdlib/servers.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def __init__(self, address_or_socket, handler, ioloop=None, backlog=100):
self.ip_map = []
# in case of FTPS class not properly configured we want errors
# to be raised here rather than later, when client connects
# if hasattr(handler, 'get_ssl_context'):
# handler.get_ssl_context(handler)
if hasattr(handler, 'validate_ssl_options'):
handler.validate_ssl_options()
if callable(getattr(address_or_socket, 'listen', None)):
sock = address_or_socket
sock.setblocking(0)
Expand Down
6 changes: 3 additions & 3 deletions pyftpdlib/test/test_functional_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,15 +370,15 @@ def try_protocol_combo(self, server_protocol, client_protocol):
# for proto in protos:
# self.try_protocol_combo(ssl.PROTOCOL_TLSv1, proto)

# On OSX TLS_FTPHandler.get_ssl_context()._context does not exist.
# On OSX TLS_FTPHandler.validate_ssl_options()._context does not exist.
@unittest.skipIf(OSX, "can't get options on OSX")
def test_ssl_options(self):
from OpenSSL import SSL
from OpenSSL._util import lib
from pyftpdlib.handlers import TLS_FTPHandler
try:
TLS_FTPHandler.ssl_context = None
ctx = TLS_FTPHandler.get_ssl_context()
ctx = TLS_FTPHandler.validate_ssl_options()
# Verify default opts.
with contextlib.closing(socket.socket()) as s:
s = SSL.Connection(ctx, s)
Expand All @@ -392,7 +392,7 @@ def test_ssl_options(self):
# ssl_proto is set to SSL.SSLv23_METHOD).
TLS_FTPHandler.ssl_context = None
TLS_FTPHandler.ssl_options = None
ctx = TLS_FTPHandler.get_ssl_context()
ctx = TLS_FTPHandler.validate_ssl_options()
with contextlib.closing(socket.socket()) as s:
s = SSL.Connection(ctx, s)
opts = lib.SSL_CTX_get_options(ctx._context)
Expand Down

0 comments on commit 5737721

Please sign in to comment.