pyOpenSSL + SocketServer WIP

This commit is contained in:
Michael Lazar 2020-05-10 22:16:36 -04:00
parent 7996b49792
commit ef4023bd5c
1 changed files with 16 additions and 29 deletions

View File

@ -44,7 +44,6 @@ import pathlib
import re import re
import socket import socket
import socketserver import socketserver
import ssl
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
@ -56,6 +55,7 @@ from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import rsa
from OpenSSL import SSL
if sys.version_info < (3, 7): if sys.version_info < (3, 7):
sys.exit("Fatal Error: jetforce requires Python 3.7+") sys.exit("Fatal Error: jetforce requires Python 3.7+")
@ -693,7 +693,7 @@ class GeminiServer(socketserver.ThreadingTCPServer):
app: typing.Callable, app: typing.Callable,
host: str = "127.0.0.1", host: str = "127.0.0.1",
port: int = 1965, port: int = 1965,
ssl_context: ssl.SSLContext = None, ssl_context: SSL.Context = None,
hostname: str = "localhost", hostname: str = "localhost",
) -> None: ) -> None:
@ -723,16 +723,14 @@ class GeminiServer(socketserver.ThreadingTCPServer):
self.serve_forever() self.serve_forever()
def get_request(self): def get_request(self) -> typing.Tuple[SSL.Connection, typing.Tuple[str, int]]:
""" """
Wrap the incoming request in an SSL connection. Wrap the incoming request in an SSL connection.
""" """
# noinspection PyTupleAssignmentBalance # noinspection PyTupleAssignmentBalance
sock, client_addr = super(GeminiServer, self).get_request() sock, client_addr = super(GeminiServer, self).get_request()
ssl_sock = self.ssl_context.wrap_socket( sock = SSL.Connection(self.ssl_context, sock)
sock, server_side=True, do_handshake_on_connect=False return sock, client_addr
)
return ssl_sock, client_addr
def log_message(self, message: str) -> None: def log_message(self, message: str) -> None:
""" """
@ -790,36 +788,25 @@ def make_ssl_context(
keyfile: typing.Optional[str] = None, keyfile: typing.Optional[str] = None,
cafile: typing.Optional[str] = None, cafile: typing.Optional[str] = None,
capath: typing.Optional[str] = None, capath: typing.Optional[str] = None,
) -> ssl.SSLContext: ) -> SSL.Context:
""" """
Generate a sane default SSL context for a Gemini server. Generate a sane default SSL context for a Gemini server.
For more information on what these variables mean and what values they can
contain, see the python standard library documentation:
https://docs.python.org/3/library/ssl.html#ssl-contexts
verify_mode: ssl.CERT_OPTIONAL
A client certificate request is sent to the client. The client may
either ignore the request or send a certificate in order perform TLS
client cert authentication. If the client chooses to send a certificate,
it is verified. Any verification error immediately aborts the TLS
handshake.
""" """
if certfile is None: if certfile is None:
certfile, keyfile = generate_ad_hoc_certificate(hostname) certfile, keyfile = generate_ad_hoc_certificate(hostname)
context = ssl.SSLContext() context = SSL.Context(SSL.TLSv1_2_METHOD)
context.verify_mode = ssl.CERT_OPTIONAL context.use_certificate_file(certfile)
context.load_cert_chain(certfile, keyfile) context.use_privatekey_file(keyfile or certfile)
context.check_privatekey()
if not cafile and not capath: if cafile or capath:
# Load from the system's default client CA directory
context.load_default_certs(purpose=ssl.Purpose.CLIENT_AUTH)
else:
# Use a custom CA for validating client certificates
context.load_verify_locations(cafile, capath) context.load_verify_locations(cafile, capath)
def verify_cb(connection, x509, err_no, err_depth, return_code):
pass
context.set_verify(SSL.VERIFY_PEER, verify_cb)
return context return context