From 8079036c75f1e1b686ba03189d42fb6cc86633a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Sat, 2 Apr 2022 00:08:27 +0000 Subject: [PATCH] easyrsa: use env variables --- api/kiwi_vpn_api/easyrsa.py | 128 +++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 60 deletions(-) diff --git a/api/kiwi_vpn_api/easyrsa.py b/api/kiwi_vpn_api/easyrsa.py index 0b79386..e3a6339 100644 --- a/api/kiwi_vpn_api/easyrsa.py +++ b/api/kiwi_vpn_api/easyrsa.py @@ -80,22 +80,22 @@ class DistinguishedName(BaseModel): return result @property - def easyrsa_args(self) -> list[str]: + def easyrsa_env(self) -> dict[str, str]: """ Pass this DN as arguments to easyrsa """ - return [ - "--dn-mode=org", + return { + "EASYRSA_DN": "org", - f"--req-c={self.country}", - f"--req-st={self.state}", - f"--req-city={self.city}", - f"--req-org={self.organization}", - f"--req-ou={self.organizational_unit}", - f"--req-email={self.email}", - f"--req-cn={self.common_name}", - ] + "EASYRSA_REQ_COUNTRY": self.country, + "EASYRSA_REQ_PROVINCE": self.state, + "EASYRSA_REQ_CITY": self.city, + "EASYRSA_REQ_ORG": self.organization, + "EASYRSA_REQ_OU": self.organizational_unit, + "EASYRSA_REQ_EMAIL": self.email, + "EASYRSA_REQ_CN": self.common_name, + } class CertificateType(Enum): @@ -116,6 +116,30 @@ class EasyRSA: Represents an EasyRSA PKI. """ + __mapKeyAlgorithm = { + KeyAlgorithm.rsa2048: { + "EASYRSA_ALGO": "rsa", + "EASYRSA_KEY_SIZE": "2048", + }, + KeyAlgorithm.rsa4096: { + "EASYRSA_ALGO": "rsa", + "EASYRSA_KEY_SIZE": "2048", + }, + KeyAlgorithm.secp256r1: { + "EASYRSA_ALGO": "ec", + "EASYRSA_CURVE": "secp256r1", + }, + KeyAlgorithm.secp384r1: { + "EASYRSA_ALGO": "ec", + "EASYRSA_CURVE": "secp384r1", + }, + KeyAlgorithm.ed25519: { + "EASYRSA_ALGO": "ed", + "EASYRSA_CURVE": "ed25519", + }, + None: {}, + } + @property def output_directory(self) -> Path: """ @@ -146,7 +170,8 @@ class EasyRSA: def __easyrsa( self, - *easyrsa_args: str, + *easyrsa_cmd: str, + **easyrsa_env: str, ) -> subprocess.CompletedProcess: """ Call the `easyrsa` executable @@ -154,10 +179,14 @@ class EasyRSA: return subprocess.run( [ - "easyrsa", "--batch", - f"--pki-dir={self.output_directory}", - *easyrsa_args, + "/usr/local/bin/easyrsa", + *easyrsa_cmd, ], + env={ + "EASYRSA_BATCH": "1", + "EASYRSA_PKI": str(self.output_directory), + **easyrsa_env, + }, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True, ) @@ -165,8 +194,8 @@ class EasyRSA: def __build_cert( self, cert_filename: Path, - expiry_days: int | None, - *easyrsa_args: str, + *easyrsa_cmd: str, + **easyrsa_env: str, ) -> crypto.X509: """ Create an X.509 certificate @@ -174,45 +203,28 @@ class EasyRSA: config = Config._ - # always include password options - extra_args: list[str] = [ - f"--passout=pass:{self.ca_password}", - f"--passin=pass:{self.ca_password}", - ] + if ((algorithm := config.crypto.key_algorithm) + not in EasyRSA.__mapKeyAlgorithm): + raise ValueError(f"Unexpected algorithm: {algorithm}") - # if given, include expiry option - if expiry_days is not None: - extra_args += [f"--days={expiry_days}"] + # include expiry options + if (ca_expiry_days := config.crypto.ca_expiry_days) is not None: + easyrsa_env["EASYRSA_CA_EXPIRE"] = str(ca_expiry_days) - # if configured, include algorithm option - if (algorithm := config.crypto.key_algorithm) is not None: - args_map = { - KeyAlgorithm.rsa2048: [ - "--use-algo=rsa", "--keysize=2048" - ], - KeyAlgorithm.rsa2048: [ - "--use-algo=rsa", "--keysize=2048" - ], - KeyAlgorithm.secp256r1: [ - "--use-algo=ec", "--curve=secp256r1" - ], - KeyAlgorithm.secp384r1: [ - "--use-algo=ec", "--curve=secp384r1" - ], - KeyAlgorithm.ed25519: [ - "--use-algo=ed", "--curve=ed25519" - ] - } - - if algorithm not in args_map: - raise ValueError(f"Unexpected algorithm: {algorithm}") - - extra_args += args_map[algorithm] + if (cert_expiry_days := config.crypto.cert_expiry_days) is not None: + easyrsa_env["EASYRSA_CERT_EXPIRE"] = str(cert_expiry_days) # call easyrsa self.__easyrsa( - *extra_args, - *easyrsa_args + *easyrsa_cmd, + + # include CA password + EASYRSA_PASSOUT=f"pass:{self.ca_password}", + EASYRSA_PASSIN=f"pass:{self.ca_password}", + + # include algorithm options + **EasyRSA.__mapKeyAlgorithm[algorithm], + **easyrsa_env, ) # parse the new certificate @@ -237,12 +249,10 @@ class EasyRSA: cert = self.__build_cert( Path("ca.crt"), - Config._.crypto.ca_expiry_days, - - "--dn-mode=cn_only", - "--req-cn=kiwi-vpn-ca", - "build-ca", + + EASYRSA_DN="cn_only", + EASYRSA_REQ_CN="kiwi-vpn-ca", ) # # this takes long! @@ -267,13 +277,11 @@ class EasyRSA: return self.__build_cert( Path(f"issued/{dn.common_name}.crt"), - Config._.crypto.cert_expiry_days, - - *dn.easyrsa_args, - f"build-{cert_type}-full", dn.common_name, "nopass", + + **dn.easyrsa_env, )