identity: move client cert command to config

This commit is contained in:
dece 2021-05-29 16:43:44 +02:00
parent 448ae873a0
commit bde207768a
5 changed files with 39 additions and 15 deletions

View file

@ -352,8 +352,9 @@ def create_identity(browser: Browser, url: str):
return None return None
browser.set_status("Generating certificate…") browser.set_status("Generating certificate…")
gen_command = browser.config["generate_client_cert_command"]
try: try:
mangled_name = create_certificate(url, common_name) mangled_name = create_certificate(url, common_name, gen_command)
except ClientCertificateException as exc: except ClientCertificateException as exc:
browser.set_status_error(exc.message) browser.set_status_error(exc.message)
return None return None

View file

@ -16,6 +16,18 @@ DEFAULT_CONFIG = {
"external_command_default": ["xdg-open"], "external_command_default": ["xdg-open"],
"home": "bebop:welcome", "home": "bebop:welcome",
"render_mode": "fancy", "render_mode": "fancy",
"generate_client_cert_command": [
"openssl", "req",
"-newkey", "rsa:4096",
"-nodes",
"-keyform", "PEM",
"-keyout", "{key_path}",
"-x509",
"-days", "28140", # https://www.youtube.com/watch?v=F9L4q-0Pi4E
"-outform", "PEM",
"-out", "{cert_path}",
"-subj", "/CN={common_name}",
],
} }
RENDER_MODES = ("fancy", "dumb") RENDER_MODES = ("fancy", "dumb")

View file

@ -68,6 +68,7 @@ Here are the available options:
* external_command_default (see note 1): default command to open files. * external_command_default (see note 1): default command to open files.
* home (string): home page. * home (string): home page.
* render_mode (string): default render mode to use ("fancy" or "dumb"). * render_mode (string): default render mode to use ("fancy" or "dumb").
* generate_client_cert_command (see note 3): command to generate a client cert.
Notes: Notes:
@ -75,6 +76,8 @@ Notes:
2: the external_commands dict maps MIME types to commands just as above. For example, if you want to open video files with VLC and audio files in Clementine, you can use the following dict: `{"audio": ["clementine"], "video": ["vlc"]}`. For now only "main" MIME types are supported, i.e. you cannot specify precise types like "audio/flac", just "audio". 2: the external_commands dict maps MIME types to commands just as above. For example, if you want to open video files with VLC and audio files in Clementine, you can use the following dict: `{"audio": ["clementine"], "video": ["vlc"]}`. For now only "main" MIME types are supported, i.e. you cannot specify precise types like "audio/flac", just "audio".
3: the generate_client_cert_command uses the same format as other commands (specified in note 1 above), with the exception that if the strings "{cert_path}", "{key_path}" or "{common_name}" are present in any string for the list, they will be replaced respectively by the certificate output path, the key output path and the CN to use.
Your current configuration is: Your current configuration is:
""" """

View file

@ -83,24 +83,23 @@ def get_cert_and_key(cert_id: str):
return directory / f"{cert_id}.crt", directory / f"{cert_id}.key" return directory / f"{cert_id}.crt", directory / f"{cert_id}.key"
def create_certificate(url: str, common_name: str): def create_certificate(url: str, common_name: str, gen_command: list):
"""Create a secure self-signed certificate using system's OpenSSL.""" """Create a secure self-signed certificate using system's OpenSSL."""
identities_path = get_identities_path() identities_path = get_identities_path()
mangled_name = get_mangled_name(url, common_name) mangled_name = get_mangled_name(url, common_name)
cert_path = identities_path / f"{mangled_name}.crt" cert_path = identities_path / f"{mangled_name}.crt"
key_path = identities_path / f"{mangled_name}.key" key_path = identities_path / f"{mangled_name}.key"
command = [
"openssl", "req", command = []
"-newkey", "rsa:4096", for part in gen_command:
"-nodes", if "{key_path}" in part:
"-keyform", "PEM", part = part.format(key_path=str(key_path))
"-keyout", str(key_path), if "{cert_path}" in part:
"-x509", part = part.format(cert_path=str(cert_path))
"-days", "28140", # https://www.youtube.com/watch?v=F9L4q-0Pi4E if "{common_name}" in part:
"-outform", "PEM", part = part.format(common_name=common_name)
"-out", str(cert_path), command.append(part)
"-subj", f"/CN={common_name}",
]
try: try:
subprocess.check_call( subprocess.check_call(
command, command,

View file

@ -1,5 +1,6 @@
"""Gemini protocol implementation.""" """Gemini protocol implementation."""
import logging
import re import re
import socket import socket
import ssl import ssl
@ -157,7 +158,15 @@ class Request:
# Setup TLS. # Setup TLS.
context = Request.get_ssl_context() context = Request.get_ssl_context()
if self.identity: if self.identity:
try:
context.load_cert_chain(*self.identity) context.load_cert_chain(*self.identity)
except FileNotFoundError as exc:
sock.close()
self.state = Request.STATE_CONNECTION_FAILED
self.error = "Could not load identity files."
logging.error(f"Failed to load identity files {self.identity}")
return False
try: try:
self.ssock = context.wrap_socket(sock, server_hostname=hostname) self.ssock = context.wrap_socket(sock, server_hostname=hostname)
except OSError as exc: except OSError as exc: