def test_read_time_tolerance_input_issues(): config_string = f""" validation-contexts: default: time-tolerance: "this makes no sense" trust: '{TESTING_CA_DIR}/root/root.cert.pem' """ with pytest.raises(ConfigurationError, match='time-tolerance.*'): cli_config: config.CLIConfig = config.parse_cli_config(config_string) cli_config.get_validation_context(as_dict=True) config_string = f""" time-tolerance: "this makes no sense" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/root.cert.pem' """ with pytest.raises(ConfigurationError, match='time-tolerance.*'): cli_config: config.CLIConfig = config.parse_cli_config(config_string) cli_config.get_validation_context(as_dict=True) vc_kwargs = init_validation_context_kwargs(trust=[], trust_replace=False, other_certs=[]) assert 'retroactive_revinfo' not in vc_kwargs assert vc_kwargs['time_tolerance'] == timedelta( seconds=DEFAULT_TIME_TOLERANCE)
def test_read_logging_config(): config_string = """ logging: root-level: DEBUG root-output: stdout by-module: example.test1: level: 50 output: test.log example.test2: level: DEBUG example.test3: level: 10 output: stderr """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) assert cli_config.log_config[None].output == StdLogOutput.STDOUT assert cli_config.log_config[None].level == 'DEBUG' assert cli_config.log_config['example.test1'].level == 50 assert cli_config.log_config['example.test1'].output == 'test.log' assert cli_config.log_config['example.test2'].level == 'DEBUG' assert cli_config.log_config['example.test2'].output == StdLogOutput.STDERR assert cli_config.log_config['example.test3'].level == 10 assert cli_config.log_config['example.test3'].output == StdLogOutput.STDERR
def test_read_retroactive_revinfo(config_string, result): cli_config: config.CLIConfig = config.parse_cli_config(config_string) vc_kwargs = cli_config.get_validation_context(as_dict=True) if result is False: assert 'retroactive_revinfo' not in vc_kwargs else: assert vc_kwargs['retroactive_revinfo']
def test_read_bad_config2(bad_type): config_string = f""" stamp-styles: default: {bad_type} """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) with pytest.raises(ConfigurationError): cli_config.get_stamp_style()
def test_read_pkcs11_config_missing_slot(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so cert-label: signer """) with pytest.raises(ConfigurationError, match='Either'): cli_config.get_pkcs11_config('foo')
def test_key_usage_errors(key_usage_str): config_string = f""" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/root.cert.pem' signer-key-usage: {key_usage_str} """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) with pytest.raises(ConfigurationError): cli_config.get_signer_key_usages()
def test_read_pkcs11_nothing_to_pull(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so token-label: testrsa cert-label: signer """) setup = cli_config.get_pkcs11_config('foo') assert len(setup.other_certs) == 0
def test_read_pkcs11_config_no_cert_spec(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so slot-no: 0 key-label: signer """) with pytest.raises(ConfigurationError, match="Either 'cert_id'"): cli_config.get_pkcs11_config('foo')
def test_read_pkcs11_config_no_key_spec(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so slot-no: 0 cert-id: "deadbeef" """) with pytest.raises(ConfigurationError, match="Either 'key_id'"): cli_config.get_pkcs11_config('foo')
def test_read_bad_background_config(): config_string = f""" stamp-styles: default: type: text background: 1234 """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) with pytest.raises(ConfigurationError, match='must be a string'): cli_config.get_stamp_style()
def test_read_pemder_config_wrong_passphrase(): cli_config = config.parse_cli_config(f""" pemder-setups: foo: key-file: '{CRYPTO_DATA_DIR}/keys-rsa/signer.key.pem' cert-file: '{TESTING_CA_DIR}/interm/signer1.cert.pem' key-passphrase: "this passphrase is wrong" """) setup = cli_config.get_pemder_config('foo') with pytest.raises(ConfigurationError): setup.instantiate()
def test_read_pemder_config_missing_passphrase(): cli_config = config.parse_cli_config(f""" pemder-setups: foo: key-file: '{CRYPTO_DATA_DIR}/keys-rsa/signer.key.pem' cert-file: '{TESTING_CA_DIR}/interm/signer1.cert.pem' """) setup = cli_config.get_pemder_config('foo') with pytest.raises(ConfigurationError): setup.instantiate() setup.instantiate(provided_key_passphrase=b'secret')
def test_read_pkcs12_config_wrong_passphrase(): cli_config = config.parse_cli_config(f""" pkcs12-setups: foo: pfx-file: '{TESTING_CA_DIR}/interm/signer1.pfx' other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' pfx-passphrase: "this passphrase is wrong" """) setup = cli_config.get_pkcs12_config('foo') with pytest.raises(ConfigurationError): setup.instantiate()
def test_read_key_usage(key_usage_str, key_usages): config_string = f""" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/root.cert.pem' signer-key-usage: {key_usage_str} """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) key_usage_settings = cli_config.get_signer_key_usages() assert key_usage_settings.key_usage == key_usages assert key_usage_settings.extd_key_usage is None
def test_read_pkcs11_config_ids(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so slot-no: 0 cert-id: 5 key-id: "74657374" """) setup = cli_config.get_pkcs11_config('foo') assert setup.cert_id == b'\x05' assert setup.key_id == b'test'
def test_read_pkcs11_config_external_cert(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so slot-no: 0 key-id: 10 signing-certificate: '{TESTING_CA_DIR}/interm/signer1.cert.pem' """) setup = cli_config.get_pkcs11_config('foo') assert setup.cert_id is None assert setup.cert_label is None assert isinstance(setup.signing_certificate, x509.Certificate)
def test_read_pkcs12_config_null_pw(): cli_config = config.parse_cli_config(f""" pkcs12-setups: foo: pfx-file: '{TESTING_CA_DIR}/interm/signer1.pfx' other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' pfx-passphrase: null """) setup = cli_config.get_pkcs12_config('foo') assert len(setup.other_certs) == 2 signer = setup.instantiate() _signer_sanity_check(signer)
def test_read_pkcs11_config_slot_no(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so slot-no: 0 cert-label: signer other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' """) setup = cli_config.get_pkcs11_config('foo') assert setup.module_path == '/path/to/libfoo.so' assert setup.slot_no == 0 assert len(setup.other_certs) == 2
def test_read_logging_config_defaults(): cli_config: config.CLIConfig = config.parse_cli_config(""" logging: root-level: DEBUG """) assert cli_config.log_config[None].output == StdLogOutput.STDERR assert cli_config.log_config[None].level == 'DEBUG' assert list(cli_config.log_config.keys()) == [None] cli_config: config.CLIConfig = config.parse_cli_config(""" logging: root-output: 'test.log' """) assert cli_config.log_config[None].output == 'test.log' assert cli_config.log_config[None].level == DEFAULT_ROOT_LOGGER_LEVEL assert list(cli_config.log_config.keys()) == [None] cli_config: config.CLIConfig = config.parse_cli_config("") assert cli_config.log_config[None].output == StdLogOutput.STDERR assert cli_config.log_config[None].level == DEFAULT_ROOT_LOGGER_LEVEL assert list(cli_config.log_config.keys()) == [None]
def test_read_pkcs12_config(): cli_config = config.parse_cli_config(f""" pkcs12-setups: foo: pfx-file: '{TESTING_CA_DIR}/interm/signer1.pfx' other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' """) setup = cli_config.get_pkcs12_config('foo') with pytest.raises(ConfigurationError): cli_config.get_pkcs12_config('bar') assert len(setup.other_certs) == 2 signer = setup.instantiate() _signer_sanity_check(signer)
def cli(ctx, config, verbose): config_text = None if config is None: try: with open(DEFAULT_CONFIG_FILE, 'r') as f: config_text = f.read() config = DEFAULT_CONFIG_FILE except FileNotFoundError: pass except IOError as e: raise click.ClickException( f"Failed to read {DEFAULT_CONFIG_FILE}: {str(e)}") else: try: config_text = config.read() except IOError as e: raise click.ClickException( f"Failed to read configuration: {str(e)}", ) ctx.ensure_object(dict) if config_text is not None: ctx.obj[Ctx.CLI_CONFIG] = cfg = parse_cli_config(config_text) log_config = cfg.log_config else: # grab the default log_config = parse_logging_config({}) if verbose: # override the root logger's logging level, but preserve the output root_logger_config = log_config[None] log_config[None] = LogConfig(level=logging.DEBUG, output=root_logger_config.output) elif 'fontTools.subset' not in log_config: # the fontTools subsetter has a very noisy INFO log, so # set that one to WARNING by default log_config['fontTools.subset'] = LogConfig( level=logging.WARNING, # use the root logger's output settings to populate the default output=log_config[None].output) logging_setup(log_config) if verbose: logging.debug("Running with --verbose") if config_text is not None: logging.debug(f'Finished reading configuration from {config}.') else: logging.debug('There was no configuration to parse.')
def test_read_pkcs11_config(): cli_config = config.parse_cli_config(f""" pkcs11-setups: foo: module-path: /path/to/libfoo.so token-label: testrsa cert-label: signer other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' """) setup = cli_config.get_pkcs11_config('foo') with pytest.raises(ConfigurationError): cli_config.get_pkcs11_config('bar') assert setup.token_label == 'testrsa' assert setup.module_path == '/path/to/libfoo.so' assert len(setup.other_certs) == 2
def test_read_key_usage_policy_2(): config_string = f""" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/root.cert.pem' signer-key-usage-policy: key-usage: [digital_signature, non_repudiation] extd-key-usage: '2.999' explicit-extd-key-usage-required: true """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) key_usage_settings = cli_config.get_signer_key_usages() assert key_usage_settings.key_usage \ == {'digital_signature', 'non_repudiation'} assert key_usage_settings.extd_key_usage == {'2.999'} assert key_usage_settings.explicit_extd_key_usage_required
def test_read_key_usage_policy_3(): config_string = f""" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/root.cert.pem' signer-key-usage-policy: key-usage: [digital_signature, non_repudiation] key-usage-forbidden: data_encipherment """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) key_usage_settings = cli_config.get_signer_key_usages() assert key_usage_settings.key_usage \ == {'digital_signature', 'non_repudiation'} assert key_usage_settings.key_usage_forbidden == {'data_encipherment'} assert key_usage_settings.extd_key_usage is None assert not key_usage_settings.match_all_key_usages
def test_default_stamp_style_fetch(): # regression test for fetching the default stamp style if not explicitly # defined config_string = f""" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/root.cert.pem' other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) result = cli_config.get_stamp_style(None) from pyhanko.sign import DEFAULT_SIGNING_STAMP_STYLE assert result == DEFAULT_SIGNING_STAMP_STYLE
def test_read_qr_config(): from pyhanko_tests.test_utils import NOTO_SERIF_JP from pyhanko.pdf_utils.font import GlyphAccumulatorFactory, SimpleFontEngine config_string = f""" stamp-styles: default: text-box-style: font: {NOTO_SERIF_JP} type: qr background: __stamp__ alternative1: text-box-style: font: {NOTO_SERIF_JP} background: pyhanko_tests/data/img/stamp-indexed.png type: qr alternative2: type: qr alternative3: type: text """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) default_qr_style = cli_config.get_stamp_style() assert isinstance(default_qr_style, QRStampStyle) assert default_qr_style.background is stamp.STAMP_ART_CONTENT assert isinstance(default_qr_style.text_box_style.font, GlyphAccumulatorFactory) alternative1 = cli_config.get_stamp_style('alternative1') assert isinstance(alternative1, QRStampStyle) assert isinstance(alternative1.background, PdfImage) assert isinstance(alternative1.text_box_style.font, GlyphAccumulatorFactory) alternative2 = cli_config.get_stamp_style('alternative2') assert isinstance(alternative2, QRStampStyle) assert alternative2.background is None assert isinstance(alternative2.text_box_style.font, SimpleFontEngine) alternative3 = cli_config.get_stamp_style('alternative3') assert isinstance(alternative3, TextStampStyle) assert alternative3.background is None assert isinstance(alternative3.text_box_style.font, SimpleFontEngine) with pytest.raises(ConfigurationError): cli_config.get_stamp_style('theresnosuchstyle')
def test_read_pemder_config(): cli_config = config.parse_cli_config(f""" pemder-setups: foo: key-file: '{CRYPTO_DATA_DIR}/keys-rsa/signer.key.pem' cert-file: '{TESTING_CA_DIR}/interm/signer1.cert.pem' other-certs: '{TESTING_CA_DIR}/ca-chain.cert.pem' key-passphrase: secret """) setup = cli_config.get_pemder_config('foo') with pytest.raises(ConfigurationError): cli_config.get_pemder_config('bar') assert len(setup.other_certs) == 2 signer = setup.instantiate() _signer_sanity_check(signer)
def test_read_vc_kwargs(trust_replace): config_string = f""" validation-contexts: default: trust: '{TESTING_CA_DIR}/root/certs/ca.cert.pem' trust-replace: {'true' if trust_replace else 'false'} other-certs: '{TESTING_CA_DIR}/intermediate/certs/ca-chain.cert.pem' """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) vc_kwargs = cli_config.get_validation_context(as_dict=True) assert len(vc_kwargs['other_certs']) == 2 if trust_replace: assert 'extra_trust_roots' not in vc_kwargs assert len(vc_kwargs['trust_roots']) == 1 else: assert 'trust_roots' not in vc_kwargs assert len(vc_kwargs['extra_trust_roots']) == 1 with pytest.raises(ConfigurationError): cli_config.get_validation_context('theresnosuchvc')
def test_read_time_tolerance(config_string, result): cli_config: config.CLIConfig = config.parse_cli_config(config_string) vc_kwargs = cli_config.get_validation_context(as_dict=True) assert vc_kwargs['time_tolerance'] == timedelta(seconds=result)
def test_read_qr_config(): from pyhanko.pdf_utils.font import SimpleFontEngineFactory from pyhanko.pdf_utils.font.opentype import GlyphAccumulatorFactory from pyhanko_tests.test_text import NOTO_SERIF_JP config_string = f""" stamp-styles: default: text-box-style: font: {NOTO_SERIF_JP} type: qr background: __stamp__ qr-position: right inner-content-layout: y-align: bottom x-align: mid margins: left: 10 right: 10 alternative1: text-box-style: font: {NOTO_SERIF_JP} background: pyhanko_tests/data/img/stamp-indexed.png type: qr alternative2: type: qr background: pyhanko_tests/data/pdf/pdf-background-test.pdf alternative3: type: text wrong-position: type: qr qr-position: bleh """ cli_config: config.CLIConfig = config.parse_cli_config(config_string) default_qr_style = cli_config.get_stamp_style() assert isinstance(default_qr_style, QRStampStyle) assert default_qr_style.background is stamp.STAMP_ART_CONTENT assert isinstance(default_qr_style.text_box_style.font, GlyphAccumulatorFactory) assert default_qr_style.qr_position == stamp.QRPosition.RIGHT_OF_TEXT expected_layout = layout.SimpleBoxLayoutRule( x_align=layout.AxisAlignment.ALIGN_MID, y_align=layout.AxisAlignment.ALIGN_MIN, margins=layout.Margins(left=10, right=10)) assert default_qr_style.inner_content_layout == expected_layout alternative1 = cli_config.get_stamp_style('alternative1') assert isinstance(alternative1, QRStampStyle) assert isinstance(alternative1.background, PdfImage) assert isinstance(alternative1.text_box_style.font, GlyphAccumulatorFactory) assert alternative1.qr_position == stamp.QRPosition.LEFT_OF_TEXT alternative2 = cli_config.get_stamp_style('alternative2') assert isinstance(alternative2, QRStampStyle) assert isinstance(alternative2.background, ImportedPdfPage) assert isinstance(alternative2.text_box_style.font, SimpleFontEngineFactory) alternative3 = cli_config.get_stamp_style('alternative3') assert isinstance(alternative3, TextStampStyle) assert alternative3.background is None assert isinstance(alternative3.text_box_style.font, SimpleFontEngineFactory) with pytest.raises(ConfigurationError, match='not a valid QR position'): cli_config.get_stamp_style('wrong-position') with pytest.raises(ConfigurationError): cli_config.get_stamp_style('theresnosuchstyle')