From 7759264b3785966b724e0816b353494fae17e80f Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Wed, 11 Dec 2024 13:57:12 +0100 Subject: [PATCH] Added self-signed SSL certificate generator --- sbapp/sideband/certgen.py | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 sbapp/sideband/certgen.py diff --git a/sbapp/sideband/certgen.py b/sbapp/sideband/certgen.py new file mode 100644 index 0000000..c403f26 --- /dev/null +++ b/sbapp/sideband/certgen.py @@ -0,0 +1,79 @@ +KEY_PASSPHRASE = None +LOADED_KEY = None + +import os +import RNS +import datetime +from cryptography import x509 +from cryptography.x509.oid import NameOID +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.serialization import load_pem_private_key + +from cryptography import __version__ as cryptography_version_str +try: + cryptography_major_version = int(cryptography_version_str.split(".")[0]) +except: + RNS.log(f"Could not determine PyCA/cryptography version: {e}", RNS.LOG_ERROR) + RNS.log(f"Assuming recent version with automatic backend selection", RNS.LOG_ERROR) + +def get_key(key_path, force_reload=False): + KEY_PATH = key_path + key = None + if LOADED_KEY != None and not force_reload: + return LOADED_KEY + elif os.path.isfile(KEY_PATH): + with open(KEY_PATH, "rb") as f: + key = load_pem_private_key(f.read(), KEY_PASSPHRASE) + else: + if cryptography_major_version > 3: + key = ec.generate_private_key(curve=ec.SECP256R1()) + else: + from cryptography.hazmat.backends import default_backend + key = ec.generate_private_key(curve=ec.SECP256R1(), backend=default_backend()) + + if KEY_PASSPHRASE == None: + key_encryption = serialization.NoEncryption() + else: + key_encryption = serialization.BestAvailableEncryption(KEY_PASSPHRASE) + + with open(KEY_PATH, "wb") as f: + f.write(key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=key_encryption)) + + return key + +def gen_cert(cert_path, key): + CERT_PATH = cert_path + cert_attrs = [x509.NameAttribute(NameOID.COUNTRY_NAME, "NA"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "None"), + x509.NameAttribute(NameOID.LOCALITY_NAME, "Earth"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Sideband"), + x509.NameAttribute(NameOID.COMMON_NAME, "Sideband Repository")] + + issuer = x509.Name(cert_attrs) + subject = issuer + + cb = x509.CertificateBuilder() + cb = cb.subject_name(subject) + cb = cb.issuer_name(issuer) + cb = cb.public_key(key.public_key()) + cb = cb.serial_number(x509.random_serial_number()) + cb = cb.not_valid_before(datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(days=-14)) + cb = cb.not_valid_after(datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(days=3652)) + cb = cb.add_extension(x509.SubjectAlternativeName([x509.DNSName("localhost")]), critical=False) + if cryptography_major_version > 3: + cert = cb.sign(key, hashes.SHA256()) + else: + from cryptography.hazmat.backends import default_backend + cert = cb.sign(key, hashes.SHA256(), backend=default_backend()) + + with open(CERT_PATH, "wb") as f: + f.write(cert.public_bytes(serialization.Encoding.PEM)) + +def ensure_certificate(key_path, cert_path): + gen_cert(cert_path, get_key(key_path)) + return cert_path \ No newline at end of file