From de89a24a6a5ee855cad05921792ad57a5a9d1207 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Mon, 7 Nov 2022 21:38:05 +0100 Subject: ... --- tools/ca/ca/__main__.py | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/ca/ca/__main__.py b/tools/ca/ca/__main__.py index e3e4bbe6..118b3763 100644 --- a/tools/ca/ca/__main__.py +++ b/tools/ca/ca/__main__.py @@ -30,6 +30,7 @@ from tempfile import TemporaryFile import subprocess import json from leapseconddata import LeapSecondData +from collections.abc import Iterable class KeyType(Enum): @@ -76,6 +77,28 @@ class KeyType(Enum): except KeyError: raise ValueError() +class SupportedKeyUsage(Enum): + SERVER_AUTH = 'server' + CLIENT_AUTH = 'client' + + @property + def oid(self): + match self: + case SupportedKeyUsage.SERVER_AUTH: + return ExtendedKeyUsageOID.SERVER_AUTH + case SupportedKeyUsage.CLIENT_AUTH: + return ExtendedKeyUsageOID.CLIENT_AUTH + + def __str__(self): + return self.value + + @classmethod + def from_string(cls, s): + try: + return cls(s) + except KeyError: + raise ValueError() + class ValidFQDN(FQDN): def __init__(self, *args, **kwds): super().__init__(*args, **kwds) @@ -133,6 +156,19 @@ class BooleanAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, False if option_string.startswith('--no') else True) +class ExtendAction(argparse.Action): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.reset_dest = False + def __call__(self, parser, namespace, values, option_string=None): + if not self.reset_dest: + setattr(namespace, self.dest, []) + self.reset_dest = True + if isinstance(values, Iterable): + getattr(namespace, self.dest).extend(values) + else: + getattr(namespace, self.dest).append(values) + def load_key(keyfile, prompt='CA private key password: '): key = None @@ -294,7 +330,10 @@ def initca(ca_cert, ca_key, key_type, subject, clock_skew, validity, sops): logger.debug('Adjusting permissions for ā€˜%sā€™...', ca_cert) os.chmod(ca_cert, 0o0444) -def signcsr(ca_cert, ca_key, clock_skew, validity, subject, alternative_name, ignore_alternative_names, csr, output): +def signcsr(ca_cert, ca_key, clock_skew, validity, subject, alternative_name, key_usage, ignore_alternative_names, csr, output): + if not key_usage: + raise InvalidParamsError('No extended key usages specified') + csr_bytes = None try: csr_bytes = csr.read() @@ -348,7 +387,7 @@ def signcsr(ca_cert, ca_key, clock_skew, validity, subject, alternative_name, ig x509.BasicConstraints(ca=False, path_length=None), True ).add_extension( - x509.ExtendedKeyUsage([ExtendedKeyUsageOID.CLIENT_AUTH]), + x509.ExtendedKeyUsage(list(map(lambda ku: ku.oid, key_usage))), False ) @@ -374,7 +413,7 @@ def signcsr(ca_cert, ca_key, clock_skew, validity, subject, alternative_name, ig logger.debug('Adjusting permissions for ā€˜%sā€™...', output) os.chmod(output, 0o0444) -def new_client(ca_cert, ca_key, key_type, clock_skew, validity, subject, alternative_name, sops, output): +def new_client(ca_cert, ca_key, key_type, clock_skew, validity, subject, alternative_name, key_usage, sops, output): key_file = output.with_suffix('.key') cert_file = output.with_suffix('.crt') @@ -417,6 +456,7 @@ def new_client(ca_cert, ca_key, key_type, clock_skew, validity, subject, alterna validity=validity, subject=None, alternative_name=[], + key_usage=key_usage, ignore_alternative_names=False, output=cert_file, csr=csr.sign( @@ -524,6 +564,7 @@ def main(): subparser.add_argument('--validity', metavar='DURATION', type=duration, default=timedelta(days=ceil(365.2425*10))) subparser.add_argument('--subject', metavar='CN', type=str, required=False) subparser.add_argument('--ignore-alternative-names', '--no-ignore-alternative-names', action=BooleanAction, default=True) + subparser.add_argument('--key-usage', metavar='KEY_USAGE', type=SupportedKeyUsage, action=ExtendAction, default=[SupportedKeyUsage.CLIENT_AUTH]) subparser.add_argument('--alternative-name', metavar='CN', type=str, action='append') subparser.add_argument('--output', type=Path, required=True) subparser.add_argument('csr', metavar='FILE', type=argparse.FileType(mode='rb')) @@ -537,6 +578,7 @@ def main(): subparser.add_argument('--validity', metavar='DURATION', type=duration, default=timedelta(days=ceil(365.2425*10))) subparser.add_argument('--sops', '--no-sops', action=BooleanAction, default=True) subparser.add_argument('--subject', metavar='CN', type=str, required=True) + subparser.add_argument('--key-usage', metavar='KEY_USAGE', type=SupportedKeyUsage, action=ExtendAction, default=[SupportedKeyUsage.CLIENT_AUTH]) subparser.add_argument('--alternative-name', metavar='CN', type=str, action='append') subparser.add_argument('--output', type=Path, required=True) subparser.set_defaults(cmd=new_client) -- cgit v1.2.3