actually issuing certs

This commit is contained in:
Jörn-Michael Miehe 2022-03-30 22:27:17 +00:00
parent 23a806e325
commit 2566702d9e
2 changed files with 52 additions and 26 deletions

View file

@ -194,7 +194,7 @@ class LockableCountry(LockableString):
value: constr(max_length=2) value: constr(max_length=2)
class DNParts(BaseModel): class ServerDN(BaseModel):
""" """
This server's "distinguished name" This server's "distinguished name"
""" """
@ -204,6 +204,8 @@ class DNParts(BaseModel):
city: LockableString city: LockableString
organization: LockableString organization: LockableString
organizational_unit: LockableString organizational_unit: LockableString
email: LockableString
common_name: str
class CertificateAlgo(Enum): class CertificateAlgo(Enum):
@ -227,9 +229,10 @@ class CryptoConfig(BaseModel):
schemes: list[str] = ["bcrypt"] schemes: list[str] = ["bcrypt"]
# pki settings # pki settings
ca_password: str | None
cert_algo: CertificateAlgo | None cert_algo: CertificateAlgo | None
expiry_days: int | None ca_password: str | None
ca_expiry_days: int | None
cert_expiry_days: int | None
@property @property
def context(self) -> CryptContext: def context(self) -> CryptContext:
@ -244,15 +247,13 @@ class Config(BaseModel):
Configuration for `kiwi-vpn-api` Configuration for `kiwi-vpn-api`
""" """
# common name for the server
server_name: str
# may include client-to-client, cipher etc. # may include client-to-client, cipher etc.
openvpn_extra_options: dict[str, Any] | None openvpn_extra_options: dict[str, Any] | None
db: DBConfig db: DBConfig
jwt: JWTConfig jwt: JWTConfig
crypto: CryptoConfig crypto: CryptoConfig
default_dn: DNParts server_dn: ServerDN
__singleton: Config | None = None __singleton: Config | None = None

View file

@ -9,7 +9,7 @@ from pathlib import Path
from OpenSSL import crypto from OpenSSL import crypto
from passlib import pwd from passlib import pwd
from .config import Config, Settings from .config import CertificateAlgo, Config, Settings
class EasyRSA: class EasyRSA:
@ -53,9 +53,39 @@ class EasyRSA:
def __build_cert( def __build_cert(
self, self,
cert_filename: Path, cert_filename: Path,
expiry_days: int | None,
*easyrsa_args: str, *easyrsa_args: str,
) -> crypto.X509: ) -> crypto.X509:
self.__easyrsa(*easyrsa_args) config = Config._
extra_args: tuple[str] = tuple()
if expiry_days is not None:
extra_args += tuple([f"--days={expiry_days}"])
if (algo := config.crypto.cert_algo) is not None:
if algo is CertificateAlgo.rsa2048:
extra_args += ("--use-algo=rsa", "--keysize=2048")
elif algo is CertificateAlgo.rsa4096:
extra_args += ("--use-algo=rsa", "--keysize=4096")
elif algo is CertificateAlgo.secp256r1:
extra_args += ("--use-algo=ec", "--curve=secp256r1")
elif algo is CertificateAlgo.secp384r1:
extra_args += ("--use-algo=ec", "--curve=secp384r1")
elif algo is CertificateAlgo.ed25519:
extra_args += ("--use-algo=ed", "--curve=ed25519")
else:
raise ValueError(f"Unexpected algorithm: {algo}")
self.__easyrsa(
*extra_args,
*easyrsa_args
)
with open( with open(
self.pki_directory.joinpath(cert_filename), "r" self.pki_directory.joinpath(cert_filename), "r"
@ -67,30 +97,25 @@ class EasyRSA:
def init_pki(self) -> bool: def init_pki(self) -> bool:
self.__easyrsa("init-pki") self.__easyrsa("init-pki")
def build_ca( def build_ca(self) -> crypto.X509:
self,
) -> crypto.X509:
config = Config._ config = Config._
server_dn = config.server_dn
cert = self.__build_cert( cert = self.__build_cert(
Path("ca.crt"), Path("ca.crt"),
config.crypto.ca_expiry_days,
f"--passout=pass:{self.ca_password}", f"--passout=pass:{self.ca_password}",
f"--passin=pass:{self.ca_password}", f"--passin=pass:{self.ca_password}",
# "--dn-mode=org", "--dn-mode=org",
# "--req-c=EX", f"--req-c={server_dn.country.value}",
# "--req-st=EXAMPLE", f"--req-st={server_dn.state.value}",
# "--req-city=EXAMPLE", f"--req-city={server_dn.city.value}",
# "--req-org=EXAMPLE", f"--req-org={server_dn.organization.value}",
# "--req-ou=EXAMPLE", f"--req-ou={server_dn.organizational_unit.value}",
# "--req-email=EXAMPLE", f"--req-email={server_dn.email.value}",
f"--req-cn={server_dn.common_name}",
f"--req-cn={config.server_name}",
f"--days={config.crypto.expiry_days}",
# "--use-algo=ed",
# "--curve=ed25519",
"build-ca", "build-ca",
) )
@ -100,16 +125,16 @@ class EasyRSA:
def issue( def issue(
self, self,
cert_type: str = "client",
cn: str = "kiwi-vpn-client", cn: str = "kiwi-vpn-client",
cert_type: str = "client"
) -> crypto.X509: ) -> crypto.X509:
config = Config._ config = Config._
return self.__build_cert( return self.__build_cert(
Path(f"issued/{cn}.crt"), Path(f"issued/{cn}.crt"),
config.crypto.cert_expiry_days,
f"--passin=pass:{self.ca_password}", f"--passin=pass:{self.ca_password}",
f"--days={config.crypto.expiry_days}",
f"build-{cert_type}-full", f"build-{cert_type}-full",
cn, cn,