Use cryptography to generate certificates
This commit is contained in:
parent
aef44e9db7
commit
c369c3b9fd
57
jetforce.py
57
jetforce.py
|
@ -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(),
|
||||||
|
)
|
||||||
|
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,
|
||||||
)
|
)
|
||||||
return str(certfile), str(keyfile)
|
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(
|
||||||
|
|
Loading…
Reference in New Issue