From: Evan Jones Date: Tue, 26 Jun 2012 16:17:13 +0000 (-0400) Subject: TCPServer: Do some validation of ssl_options X-Git-Tag: v2.4.0~46^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=73d26a47a0ac83c02cde023b1d31a04dc37bf19e;p=thirdparty%2Ftornado.git TCPServer: Do some validation of ssl_options Previously, errors aren't detected until a client connects. --- diff --git a/tornado/netutil.py b/tornado/netutil.py index d06a176b4..574cf72e2 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -92,6 +92,23 @@ class TCPServer(object): self._pending_sockets = [] self._started = False + # Verify the SSL options. Otherwise we don't get errors until clients + # connect. This doesn't verify that the keys are legitimate, but + # the SSL module doesn't do that until there is a connected socket + # which seems like too much work + if self.ssl_options is not None: + # Only certfile is required: it can contain both keys + if 'certfile' not in self.ssl_options: + raise KeyError('missing key "certfile" in ssl_options') + + if not os.path.exists(self.ssl_options['certfile']): + raise ValueError('certfile "%s" does not exist' % + self.ssl_options['certfile']) + if ('keyfile' in self.ssl_options and + not os.path.exists(self.ssl_options['keyfile'])): + raise ValueError('keyfile "%s" does not exist' % + self.ssl_options['keyfile']) + def listen(self, port, address=""): """Starts accepting connections on the given port. diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py index 5237e75e4..e9078da28 100644 --- a/tornado/test/httpserver_test.py +++ b/tornado/test/httpserver_test.py @@ -6,6 +6,7 @@ from tornado import httpclient, simple_httpclient, netutil from tornado.escape import json_decode, utf8, _unicode, recursive_unicode, native_str from tornado.httpserver import HTTPServer from tornado.httputil import HTTPHeaders +from tornado.ioloop import IOLoop from tornado.iostream import IOStream from tornado.simple_httpclient import SimpleAsyncHTTPClient from tornado.testing import AsyncHTTPTestCase, AsyncHTTPSTestCase, AsyncTestCase, LogTrapTestCase @@ -16,6 +17,7 @@ import shutil import socket import sys import tempfile +import unittest try: import ssl @@ -101,6 +103,35 @@ class TLSv1Test(BaseSSLTest, SSLTestMixin): return ssl.PROTOCOL_TLSv1 +class BadSSLOptionsTest(unittest.TestCase): + def test_missing_arguments(self): + application = Application() + self.assertRaises(KeyError, HTTPServer, application, ssl_options={ + "keyfile": "/__missing__.crt", + }) + + def test_missing_key(self): + '''A missing SSL key should cause an immediate exception.''' + + application = Application() + module_dir = os.path.dirname(__file__) + existing_certificate = os.path.join(module_dir, 'test.crt') + + self.assertRaises(ValueError, HTTPServer, application, ssl_options={ + "certfile": "/__mising__.crt", + }) + self.assertRaises(ValueError, HTTPServer, application, ssl_options={ + "certfile": existing_certificate, + "keyfile": "/__missing__.key" + }) + + # This actually works because both files exist + server = HTTPServer(application, ssl_options={ + "certfile": existing_certificate, + "keyfile": existing_certificate + }) + + if ssl is None: del BaseSSLTest del SSLv23Test