| 45 | |
| 46 | |
| 47 | class MITMCertManager: |
| 48 | def __init__(self): |
| 49 | self._ca_key = None |
| 50 | self._ca_cert = None |
| 51 | self._ctx_cache: dict[str, ssl.SSLContext] = {} |
| 52 | self._cert_dir = tempfile.mkdtemp(prefix="domainfront_certs_") |
| 53 | self._ensure_ca() |
| 54 | |
| 55 | def _ensure_ca(self): |
| 56 | if os.path.exists(CA_KEY_FILE) and os.path.exists(CA_CERT_FILE): |
| 57 | with open(CA_KEY_FILE, "rb") as f: |
| 58 | self._ca_key = serialization.load_pem_private_key( |
| 59 | f.read(), password=None |
| 60 | ) |
| 61 | with open(CA_CERT_FILE, "rb") as f: |
| 62 | self._ca_cert = x509.load_pem_x509_certificate(f.read()) |
| 63 | log.info("Loaded CA from %s", CA_DIR) |
| 64 | else: |
| 65 | self._create_ca() |
| 66 | |
| 67 | def _create_ca(self): |
| 68 | os.makedirs(CA_DIR, exist_ok=True) |
| 69 | |
| 70 | self._ca_key = rsa.generate_private_key( |
| 71 | public_exponent=65537, key_size=2048 |
| 72 | ) |
| 73 | subject = issuer = x509.Name([ |
| 74 | x509.NameAttribute(NameOID.COMMON_NAME, "MasterHttpRelayVPN"), |
| 75 | x509.NameAttribute(NameOID.ORGANIZATION_NAME, "MasterHttpRelayVPN"), |
| 76 | ]) |
| 77 | now = datetime.datetime.now(datetime.timezone.utc) |
| 78 | self._ca_cert = ( |
| 79 | x509.CertificateBuilder() |
| 80 | .subject_name(subject) |
| 81 | .issuer_name(issuer) |
| 82 | .public_key(self._ca_key.public_key()) |
| 83 | .serial_number(x509.random_serial_number()) |
| 84 | .not_valid_before(now) |
| 85 | .not_valid_after(now + datetime.timedelta(days=3650)) |
| 86 | .add_extension( |
| 87 | x509.BasicConstraints(ca=True, path_length=0), critical=True |
| 88 | ) |
| 89 | .add_extension( |
| 90 | x509.KeyUsage( |
| 91 | digital_signature=True, |
| 92 | key_cert_sign=True, |
| 93 | crl_sign=True, |
| 94 | content_commitment=False, |
| 95 | key_encipherment=False, |
| 96 | data_encipherment=False, |
| 97 | key_agreement=False, |
| 98 | encipher_only=False, |
| 99 | decipher_only=False, |
| 100 | ), |
| 101 | critical=True, |
| 102 | ) |
| 103 | .sign(self._ca_key, hashes.SHA256()) |
| 104 | ) |