As the title states, I'd like to figure out how to use SNI (server name indication) with the tornado webserver.
I'd like to be able to present a particular certificate based on the hostname of the given request.
As the title states, I'd like to figure out how to use SNI (server name indication) with the tornado webserver.
I'd like to be able to present a particular certificate based on the hostname of the given request.
After looking more into this I found the solution using a sni_callback from ssl.SSLContext.
That will give you a method that contains the hostname before a TLS handshake is established.
Within the servername_callback method you can then chose what certificate to load based on the hostname.
import tornado.ioloop
import tornado.web
import tornado.httpserver
import ssl
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write('Hello, world')
application = tornado.web.Application([
(r'/', MainHandler)
])
def servername_callback(sock, hostname, cb_context):
# hostname contains the hostname that the client is requesting
print("hostname", hostname)
# now that we have the hostname we can dynamically pick the correct certificate
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
# this part is up to you to store via a config file or even in a database
ssl_context.load_cert_chain(certfile="/path/to/cert", keyfile="/path/to/key")
sock.context = ssl_context
if __name__ == '__main__':
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
ssl_context.sni_callback = servername_callback
http_server = tornado.httpserver.HTTPServer(application, ssl_options=ssl_context)
http_server.listen(443)
tornado.ioloop.IOLoop.instance().start()