simplify make_ssl_context

pass ssl.Purpose explicitly, deprecate verify/check_hostname

3.10 disallows 'purpose=SERVER_AUTH' from creating server sockets.
Instead:

- pass purpose directly
- always verify
- no need to set check_hostname, already covered by purpose defaults
This commit is contained in:
Min RK
2022-07-14 11:02:44 -07:00
parent a593c6187f
commit a2a01755ec
5 changed files with 53 additions and 6 deletions

View File

@@ -11,6 +11,7 @@ import re
import secrets
import signal
import socket
import ssl
import sys
import time
from concurrent.futures import ThreadPoolExecutor
@@ -3047,7 +3048,7 @@ class JupyterHub(Application):
self.internal_ssl_key,
self.internal_ssl_cert,
cafile=self.internal_ssl_ca,
check_hostname=False,
purpose=ssl.Purpose.CLIENT_AUTH,
)
# start the webserver

View File

@@ -14,6 +14,7 @@ import logging
import os
import random
import secrets
import ssl
import sys
import warnings
from datetime import timezone

View File

@@ -15,6 +15,7 @@ Handlers and their purpose include:
import json
import os
import pprint
import ssl
import sys
from urllib.parse import urlparse
@@ -111,7 +112,9 @@ def main():
ca = os.environ.get('JUPYTERHUB_SSL_CLIENT_CA') or ''
if key and cert and ca:
ssl_context = make_ssl_context(key, cert, cafile=ca, check_hostname=False)
ssl_context = make_ssl_context(
key, cert, cafile=ca, purpose=ssl.Purpose.CLIENT_AUTH
)
server = httpserver.HTTPServer(app, ssl_options=ssl_context)
server.listen(url.port, url.hostname)

View File

@@ -47,7 +47,11 @@ def main():
ca = os.environ.get('JUPYTERHUB_SSL_CLIENT_CA') or ''
if key and cert and ca:
ssl_context = make_ssl_context(key, cert, cafile=ca, check_hostname=False)
import ssl
ssl_context = make_ssl_context(
key, cert, cafile=ca, purpose=ssl.Purpose.CLIENT_AUTH
)
assert url.scheme == "https"
server = httpserver.HTTPServer(app, ssl_options=ssl_context)

View File

@@ -94,13 +94,51 @@ def can_connect(ip, port):
return True
def make_ssl_context(keyfile, certfile, cafile=None, verify=True, check_hostname=True):
"""Setup context for starting an https server or making requests over ssl."""
def make_ssl_context(
keyfile,
certfile,
cafile=None,
verify=None,
check_hostname=None,
purpose=ssl.Purpose.SERVER_AUTH,
):
"""Setup context for starting an https server or making requests over ssl.
Used for verifying internal ssl connections.
Certificates are always verified in both directions.
Hostnames are checked for client sockets.
Client sockets are created with `purpose=ssl.Purpose.SERVER_AUTH` (default),
Server sockets are created with `purpose=ssl.Purpose.CLIENT_AUTH`.
"""
if not keyfile or not certfile:
return None
if verify is not None:
purpose = ssl.Purpose.SERVER_AUTH if verify else ssl.Purpose.CLIENT_AUTH
warnings.warn(
f"make_ssl_context(verify={verify}) is deprecated in jupyterhub 2.4."
f" Use make_ssl_context(purpose={purpose}).",
DeprecationWarning,
stacklevel=2,
)
if check_hostname is not None:
purpose = ssl.Purpose.SERVER_AUTH if check_hostname else ssl.Purpose.CLIENT_AUTH
warnings.warn(
f"make_ssl_context(check_hostname={check_hostname}) is deprecated in jupyterhub 2.4."
f" Use make_ssl_context(purpose={purpose}).",
DeprecationWarning,
stacklevel=2,
)
ssl_context = ssl.create_default_context(purpose, cafile=cafile)
# always verify
ssl_context.verify_mode = ssl.CERT_REQUIRED
if purpose == ssl.Purpose.SERVER_AUTH:
# SERVER_AUTH is authenticating servers (i.e. for a client)
ssl_context.check_hostname = True
ssl_context.load_default_certs()
ssl_context.load_cert_chain(certfile, keyfile)
ssl_context.check_hostname = check_hostname
return ssl_context