Use cryptography to generate certificates

This commit is contained in:
Michael Lazar 2020-05-09 00:58:16 -04:00
parent aef44e9db7
commit c369c3b9fd
1 changed files with 43 additions and 14 deletions

View File

@ -38,6 +38,7 @@ import argparse
import asyncio import asyncio
import codecs import codecs
import dataclasses import dataclasses
import datetime
import mimetypes import mimetypes
import os import os
import pathlib import pathlib
@ -51,6 +52,11 @@ import time
import typing import typing
import urllib.parse import urllib.parse
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
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+")
@ -756,22 +762,45 @@ class GeminiServer:
def generate_ad_hoc_certificate(hostname: str) -> typing.Tuple[str, str]: def generate_ad_hoc_certificate(hostname: str) -> typing.Tuple[str, str]:
""" """
Utility function to generate a self-signed SSL certificate key pair if Utility function to generate an ad-hoc self-signed SSL certificate.
one isn't provided. Results may vary depending on your version of OpenSSL.
""" """
certfile = pathlib.Path(tempfile.gettempdir()) / f"{hostname}.crt" certfile = os.path.join(tempfile.gettempdir(), f"{hostname}.crt")
keyfile = pathlib.Path(tempfile.gettempdir()) / f"{hostname}.key" keyfile = os.path.join(tempfile.gettempdir(), f"{hostname}.key")
if not certfile.exists() or not keyfile.exists():
print(f"Writing ad hoc TLS certificate to {certfile}") if not os.path.exists(certfile) or not os.path.exists(keyfile):
subprocess.run( backend = default_backend()
[
f"openssl req -newkey rsa:2048 -nodes -keyout {keyfile}" print("Generating private key...", file=sys.stderr)
f' -nodes -x509 -out {certfile} -subj "/CN={hostname}"' private_key = rsa.generate_private_key(65537, 2048, default_backend())
], with open(keyfile, "wb") as fp:
shell=True, # noinspection PyTypeChecker
check=True, key_data = private_key.private_bytes(
serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
) )
return str(certfile), str(keyfile) fp.write(key_data)
print("Generating certificate...", file=sys.stderr)
common_name = x509.NameAttribute(x509.NameOID.COMMON_NAME, hostname)
subject_name = x509.Name([common_name])
not_valid_before = datetime.datetime.utcnow()
not_valid_after = not_valid_before + datetime.timedelta(days=365)
certificate = x509.CertificateBuilder(
subject_name=subject_name,
issuer_name=subject_name,
public_key=private_key.public_key(),
serial_number=x509.random_serial_number(),
not_valid_before=not_valid_before,
not_valid_after=not_valid_after,
)
certificate = certificate.sign(private_key, hashes.SHA256(), backend)
with open(certfile, "wb") as fp:
# noinspection PyTypeChecker
cert_data = certificate.public_bytes(serialization.Encoding.PEM)
fp.write(cert_data)
return certfile, keyfile
def make_ssl_context( def make_ssl_context(