113 lines
2.8 KiB
Python
113 lines
2.8 KiB
Python
|
import subprocess
|
||
|
from datetime import datetime
|
||
|
from pathlib import Path
|
||
|
|
||
|
from OpenSSL import crypto
|
||
|
from passlib import pwd
|
||
|
|
||
|
|
||
|
class EasyRSA:
|
||
|
__directory: Path | None
|
||
|
__ca_password: str | None
|
||
|
|
||
|
def __init__(self, directory: Path) -> None:
|
||
|
self.__directory = directory
|
||
|
|
||
|
def set_ca_password(self, password: str | None = None) -> None:
|
||
|
if password is None:
|
||
|
password = pwd.genword(length=32, charset="ascii_62")
|
||
|
|
||
|
self.__ca_password = password
|
||
|
print(self.__ca_password)
|
||
|
|
||
|
def __easyrsa(
|
||
|
self,
|
||
|
*easyrsa_args: str,
|
||
|
) -> subprocess.CompletedProcess:
|
||
|
return subprocess.run(
|
||
|
[
|
||
|
"easyrsa", "--batch",
|
||
|
f"--pki-dir={self.__directory}",
|
||
|
*easyrsa_args,
|
||
|
],
|
||
|
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
||
|
check=True,
|
||
|
)
|
||
|
|
||
|
def __build_cert(
|
||
|
self,
|
||
|
cert_filename: Path,
|
||
|
*easyrsa_args: str,
|
||
|
) -> crypto.X509:
|
||
|
self.__easyrsa(*easyrsa_args)
|
||
|
|
||
|
with open(
|
||
|
self.__directory.joinpath(cert_filename), "r"
|
||
|
) as cert_file:
|
||
|
return crypto.load_certificate(
|
||
|
crypto.FILETYPE_PEM, cert_file.read()
|
||
|
)
|
||
|
|
||
|
def init_pki(self) -> bool:
|
||
|
self.__easyrsa("init-pki")
|
||
|
|
||
|
def build_ca(
|
||
|
self,
|
||
|
days: int = 365 * 50,
|
||
|
cn: str = "kiwi-ca"
|
||
|
) -> crypto.X509:
|
||
|
return self.__build_cert(
|
||
|
Path("ca.crt"),
|
||
|
|
||
|
f"--passout=pass:{self.__ca_password}",
|
||
|
f"--passin=pass:{self.__ca_password}",
|
||
|
|
||
|
# "--dn-mode=org",
|
||
|
# "--req-c=EX",
|
||
|
# "--req-st=EXAMPLE",
|
||
|
# "--req-city=EXAMPLE",
|
||
|
# "--req-org=EXAMPLE",
|
||
|
# "--req-ou=EXAMPLE",
|
||
|
# "--req-email=EXAMPLE",
|
||
|
|
||
|
f"--req-cn={cn}",
|
||
|
f"--days={days}",
|
||
|
|
||
|
"build-ca",
|
||
|
)
|
||
|
|
||
|
def issue(
|
||
|
self,
|
||
|
days: int = 365 * 50,
|
||
|
cn: str = "kiwi-vpn",
|
||
|
cert_type: str = "client"
|
||
|
) -> crypto.X509:
|
||
|
return self.__build_cert(
|
||
|
Path(f"issued/{cn}.crt"),
|
||
|
|
||
|
f"--passin=pass:{self.__ca_password}",
|
||
|
f"--days={days}",
|
||
|
|
||
|
f"build-{cert_type}-full",
|
||
|
cn,
|
||
|
"nopass",
|
||
|
)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
rsa = EasyRSA(Path("tmp/pki"))
|
||
|
rsa.init_pki()
|
||
|
rsa.set_ca_password()
|
||
|
|
||
|
ca = rsa.build_ca()
|
||
|
server = rsa.issue(cert_type="server", cn="kiwi-server")
|
||
|
client = rsa.issue(cert_type="client", cn="kiwi-client")
|
||
|
|
||
|
print(ca.get_subject())
|
||
|
print(server.get_subject())
|
||
|
print(client.get_subject())
|
||
|
|
||
|
date_format, encoding = "%Y%m%d%H%M%SZ", "ascii"
|
||
|
print(datetime.strptime(
|
||
|
client.get_notAfter().decode(encoding), date_format))
|