162 lines
5.2 KiB
Python
162 lines
5.2 KiB
Python
from typing import Iterable, Optional, TypeVar, Union
|
|
|
|
import click
|
|
from pyhanko_certvalidator import ValidationContext
|
|
|
|
from pyhanko.cli.config import CLIConfig
|
|
from pyhanko.cli.utils import logger, readable_file
|
|
from pyhanko.config.errors import ConfigurationError
|
|
from pyhanko.config.trust import init_validation_context_kwargs
|
|
from pyhanko.keys import load_certs_from_pemder
|
|
|
|
|
|
def build_vc_kwargs(
|
|
cli_config: Optional[CLIConfig],
|
|
validation_context: Optional[str],
|
|
trust: Union[Iterable[str], str],
|
|
trust_replace: bool,
|
|
other_certs: Union[Iterable[str], str],
|
|
retroactive_revinfo: bool,
|
|
allow_fetching: Optional[bool] = None,
|
|
):
|
|
try:
|
|
if validation_context is not None:
|
|
if any((trust, other_certs)):
|
|
raise click.ClickException(
|
|
"--validation-context is incompatible with --trust "
|
|
"and --other-certs"
|
|
)
|
|
# load the desired context from config
|
|
if cli_config is None:
|
|
raise click.ClickException("No config file specified.")
|
|
try:
|
|
result = cli_config.get_validation_context(
|
|
validation_context, as_dict=True
|
|
)
|
|
except ConfigurationError as e:
|
|
msg = (
|
|
"Configuration problem. Are you sure that the validation "
|
|
f"context '{validation_context}' is properly defined in the"
|
|
" configuration file?"
|
|
)
|
|
logger.error(msg, exc_info=e)
|
|
raise click.ClickException(msg)
|
|
elif trust or other_certs:
|
|
# load a validation profile using command line kwargs
|
|
result = init_validation_context_kwargs(
|
|
trust=trust,
|
|
trust_replace=trust_replace,
|
|
other_certs=other_certs,
|
|
retroactive_revinfo=retroactive_revinfo,
|
|
)
|
|
elif cli_config is not None:
|
|
# load the default settings from the CLI config
|
|
try:
|
|
result = cli_config.get_validation_context(as_dict=True)
|
|
except ConfigurationError as e:
|
|
msg = "Failed to load default validation context."
|
|
logger.error(msg, exc_info=e)
|
|
raise click.ClickException(msg)
|
|
else:
|
|
result = {}
|
|
|
|
if allow_fetching is not None:
|
|
result['allow_fetching'] = allow_fetching
|
|
else:
|
|
result.setdefault('allow_fetching', True)
|
|
|
|
# allow CLI --retroactive-revinfo flag to override settings
|
|
# if necessary
|
|
if retroactive_revinfo:
|
|
result['retroactive_revinfo'] = True
|
|
return result
|
|
except click.ClickException:
|
|
raise
|
|
except IOError as e:
|
|
msg = "I/O problem while reading validation config"
|
|
logger.error(msg, exc_info=e)
|
|
raise click.ClickException(msg)
|
|
except Exception as e:
|
|
msg = "Generic processing problem while reading validation config"
|
|
logger.error(msg, exc_info=e)
|
|
raise click.ClickException(msg)
|
|
|
|
|
|
def _get_key_usage_settings(ctx: click.Context, validation_context: str):
|
|
cli_config: Optional[CLIConfig] = ctx.obj.config
|
|
if cli_config is None:
|
|
return None
|
|
|
|
# note: validation_context can be None, this triggers fallback to the
|
|
# default validation context specified in the configuration file
|
|
# If we add support for specifying key usage settings as CLI arguments,
|
|
# using the same fallbacks as _build_cli_kwargs would probably be cleaner
|
|
return cli_config.get_signer_key_usages(name=validation_context)
|
|
|
|
|
|
TRUST_OPTIONS = [
|
|
click.Option(
|
|
('--validation-context',),
|
|
help='use validation context from config',
|
|
required=False,
|
|
type=str,
|
|
),
|
|
click.Option(
|
|
('--trust',),
|
|
help='list trust roots (multiple allowed)',
|
|
required=False,
|
|
multiple=True,
|
|
type=readable_file,
|
|
),
|
|
click.Option(
|
|
('--trust-replace',),
|
|
help='listed trust roots supersede OS-provided trust store',
|
|
required=False,
|
|
type=bool,
|
|
is_flag=True,
|
|
default=False,
|
|
show_default=True,
|
|
),
|
|
click.Option(
|
|
('--other-certs',),
|
|
help='other certs relevant for validation',
|
|
required=False,
|
|
multiple=True,
|
|
type=readable_file,
|
|
),
|
|
]
|
|
|
|
|
|
FC = TypeVar('FC', bound=click.Command)
|
|
|
|
|
|
def trust_options(f: FC) -> FC:
|
|
f.params.extend(TRUST_OPTIONS)
|
|
return f
|
|
|
|
|
|
def _prepare_vc(vc_kwargs, soft_revocation_check, force_revinfo):
|
|
if soft_revocation_check and force_revinfo:
|
|
raise click.ClickException(
|
|
"--soft-revocation-check is incompatible with " "--force-revinfo"
|
|
)
|
|
if force_revinfo:
|
|
rev_mode = 'require'
|
|
elif soft_revocation_check:
|
|
rev_mode = 'soft-fail'
|
|
else:
|
|
rev_mode = 'hard-fail'
|
|
vc_kwargs['revocation_mode'] = rev_mode
|
|
return vc_kwargs
|
|
|
|
|
|
def grab_certs(files):
|
|
if not files:
|
|
return None
|
|
try:
|
|
return list(load_certs_from_pemder(files))
|
|
except (IOError, ValueError) as e:
|
|
raise click.ClickException(
|
|
f'Could not load certificates from {files}'
|
|
) from e
|