pyhanko-cli 0.4.2__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyhanko_cli-0.4.2/src/pyhanko_cli.egg-info → pyhanko_cli-0.5.0}/PKG-INFO +3 -3
- pyhanko_cli-0.5.0/pyhanko_testing_commons/docs_testing.py +647 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/certomancer.yml +7 -0
- pyhanko_cli-0.5.0/pyhanko_testing_commons/test_utils/live_http.py +210 -0
- pyhanko_cli-0.5.0/pyhanko_testing_commons/test_utils/live_http_fixtures.py +22 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/signing_commons.py +5 -6
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyproject.toml +4 -4
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/_root.py +2 -2
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/_trust.py +38 -34
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/signing/plugin.py +2 -1
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/config.py +3 -1
- pyhanko_cli-0.5.0/src/pyhanko/cli/version.py +2 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0/src/pyhanko_cli.egg-info}/PKG-INFO +3 -3
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko_cli.egg-info/SOURCES.txt +3 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko_cli.egg-info/requires.txt +2 -2
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/conftest.py +4 -5
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_crypt.py +1 -1
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_ltv.py +3 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_signing.py +9 -3
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_config.py +56 -2
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_runtime.py +7 -2
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/validation/test_cli_qualified_validation.py +31 -1
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/validation/test_cli_validation.py +120 -10
- pyhanko_cli-0.4.2/src/pyhanko/cli/version.py +0 -2
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/LICENSE +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/MANIFEST.in +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/README.md +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/certomancer_trust_lists.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/intermediate_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/ocsp.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/params.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/root_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/signer.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/signer2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-dsa/tsa2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/decrypter-x25519.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/decrypter-x448.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/decrypter1.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/decrypter2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/decrypter3.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/intermediate_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/ocsp.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/root_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/signer.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/signer2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/tsa2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ecdsa/tsa_rsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/intermediate_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/ocsp.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/root_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/signer.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/signer2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed25519/tsa2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/intermediate_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/ocsp.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/root_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/signer.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/signer2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-ed448/tsa2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/intermediate_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/ocsp.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/root_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/signer_mldsa44.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/signer_mldsa65.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/signer_mldsa87.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-mldsa/tsa2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/indep_tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/indep_tsa_root.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/interm_aa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/intermediate_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/leaf_aa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/ocsp.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/root_aa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/root_ca.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/signer.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/signer2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/tsa.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/keys-rsa/tsa2.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/ocsp.req.der +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/ocsp.resp.der +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/real-misissued-qtst-cert.cer +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/real-qcert.cer +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/real-qtst-cert.cer +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/selfsigned.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/selfsigned.key.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/selfsigned.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/some-chain.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/ca-chain.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/decrypter1-old.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/decrypter1.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/decrypter1.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/decrypter2.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/decrypter2.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/interm-ocsp.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/interm-ocsp.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/signer1-long.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/signer1-long.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/signer1.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/signer1.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/signer2.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/interm/signer2.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/interm.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/interm.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/root.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/root.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/tsa.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/tsa.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/tsa2.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca/root/tsa2.pfx +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca-setup/ca-setup.sh +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca-setup/openssl.base.cnf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca-setup/pkcs11-setup-certomancer.sh +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca-setup/pkcs11-setup.sh +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/testing-ca-setup/setup-params +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/crypto/tsa.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/LICENSE.Noto +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/LICENSE.SourceSerif +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/NotoSans-Regular.ttf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/NotoSansArabic-Regular.ttf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/NotoSerifJP-Regular.otf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/NotoSerifSubset.otf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/fonts/SourceSerif4-Regular.otf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/img/stamp-indexed.png +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/img/stamp.png +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/.gitignore +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/broken-objstream1.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/broken-objstream2.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/broken-objstream3.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/broken-objstream4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/broken-objstream5.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/broken-objstream6.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/certified-with-indirect-refs-in-dir.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/circular-page-tree.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/coverage-anomalies/base.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/coverage-anomalies/one-byterange.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/coverage-anomalies/signature-gap-too-big.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/coverage-anomalies/tail-uncovered.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/coverage-anomalies/weird-byterange.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/ed448-disallowed-hash.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/ed448-shake256-nolen.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/embedded-encrypted-nocf.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/empty-a4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/extensions-direct.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/extensions-indirect-not-all-paths.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/extensions-indirect.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/extensions-update-direct.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/extensions-update-indirect.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/fontembed.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-tree-circular-ref-input.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-ap-indirect-sneaky-trailer.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-no-override-appearance-stream-ap-indirect-sneaky.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-no-override-appearance-stream-ap-indirect.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-original-ap-type-wrong.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-override-appearance-stream-ap-indirect-sneaky.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-override-appearance-stream-ap-indirect.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-override-appearance-stream-sneaky.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/form-update-override-appearance-stream.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/info-bin-producer-string.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/arabic-box.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/bitmap-bg.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/code128-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/default-font.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/double-newline.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/fancy-qr-stamp-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/form-fill-result.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/four-stamps-fixed.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/four-stamps-natural.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/ja-vert-stamps.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/leaky-graphics-state-stamp-no-corr-result.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/leaky-graphics-state-stamp-result.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/multiline-textbox-nondefault-fs.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/scaled-bitmap-bg.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/source-serif-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/stamp-from-static-pdf.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/stamp-on-pdf-bg.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/text-stamp-color.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/layout-tests/undef-bg-size.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/leaky-graphics-state-doc.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/malformed-encrypt-dict1.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/malformed-encrypt-dict2.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/malformed-xref-space-padded.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-aes256-empty-encrypted-string.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-aes256-malformed-oe.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-aes256-malformed-perms.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-aes256.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-annotless.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-badxref.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-broken-xref-size.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-hybrid-xref-mswordstyle.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-hybrid-xref-weirdgen.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-hybrid-xref.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-illegal-header.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-one-field-indir-annots.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-pdf-ua-and-a.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-pubkey-aes256.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-pubkey-rc4-envelope.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-pubkey-rc4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-pubkey-unknown-envelope-alg.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-rc4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-signed-twice-both-created.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-signed-twice-no-sig-type.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-signed-twice-second-created.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-hopeless.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-hopeless2.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-hopeless3.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-obo1.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-obo2.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-obo3.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-obo4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-obo5.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-obo6.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-startxref-same-line.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-fields-aes256.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-fields-pubkey-aes256.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-fields-pubkey-rc4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-fields-signed-twice.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-fields-tagged.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-fields.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-two-pages.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-field-aes256.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-field-pubkey-aes256.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-field-pubkey-rc4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-field-rc4.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-field-tagged.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-field.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-nonexistent-refs.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-orphaned-xrefs.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-simple-form.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-textfield-group-var.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-with-textfield-group.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal-xref.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/minimal.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/no-mediabox.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pades-lta-dss-indirect-arrs-test-2.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pades-lta-dss-indirect-arrs-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pades-with-old-style-signing-cert-attr-issser.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pades-with-old-style-signing-cert-attr.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/page-tree-direct-kid.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pdf-background-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pdf-sig-with-econtent.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pubkey-3des-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pubkey-ecc-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/pubkey-rc2-test.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/safedocs/CompactedPDFSyntaxTest.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/safedocs/SOURCE +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/scribble-decomp.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/scribble-in-arr.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/scribble.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/separate-annots-kids-indir.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/sig-no-signed-attrs.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/sig-with-ski-sid.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/signed-encrypted-pubkey-with-catalog-ref.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/simple-acroform-states-ap-indirect.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/simple-acroform-states.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/source +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/struct-tree-circular-ref.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/pdf/uncompressed-objstream-sample.pdf +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/COPYRIGHT +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/eu-lotl-old.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/eu-lotl-pivot-282.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/eu-lotl-pivot-300.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/eu-lotl-pivot-335.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/eu-lotl-pivot-341.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/eu-lotl.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/pre-reanchor.cert.pem +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/tsl-be-old.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/tsl-be-v6.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/tl/tsl-ee.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/SOURCE +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/cyclic.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/dtd.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/external.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/external_file.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/quadratic.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/simple-ns.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/simple.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/xmlbomb.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/xmlbomb2.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/data/xml/bad-xml/xmp-with-harmless-entity.xml +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_data/samples.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/csc_utils/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/csc_utils/csc_dummy_client.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/layout_test_utils.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/pkcs11_utils/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/pkcs11_utils/config.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/pyhanko_testing_commons/test_utils/pkcs11_utils/fixtures.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/setup.cfg +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/__main__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/_ctx.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/cache.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/crypt.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/fields.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/signing/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/signing/pkcs11_cli.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/signing/simple.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/signing/utils.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/stamp.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/validation/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/validation/ltv.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/commands/validation/validate.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/plugin_api.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/py.typed +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/runtime.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko/cli/utils.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko_cli.egg-info/dependency_links.txt +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko_cli.egg-info/entry_points.txt +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/src/pyhanko_cli.egg-info/top_level.txt +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_field_mgmt.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_plugins.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_signing_pkcs11.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/test_cli_stamp.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/validation/__init__.py +0 -0
- {pyhanko_cli-0.4.2 → pyhanko_cli-0.5.0}/tests/validation/conftest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyhanko-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: CLI tools for stamping and signing PDF files
|
|
5
5
|
Author-email: Matthias Valvekens <dev@mvalvekens.be>
|
|
6
6
|
Maintainer-email: Matthias Valvekens <dev@mvalvekens.be>
|
|
@@ -27,8 +27,8 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
Requires-Dist: asn1crypto>=1.5.1
|
|
29
29
|
Requires-Dist: tzlocal>=4.3
|
|
30
|
-
Requires-Dist: pyhanko<0.
|
|
31
|
-
Requires-Dist: pyhanko-certvalidator<0.
|
|
30
|
+
Requires-Dist: pyhanko<0.38,>=0.37.0
|
|
31
|
+
Requires-Dist: pyhanko-certvalidator<0.33,>=0.32.0
|
|
32
32
|
Requires-Dist: pyyaml>=6.0
|
|
33
33
|
Requires-Dist: certifi>=2023.5.7
|
|
34
34
|
Requires-Dist: click!=8.2.0,>=8.1.3
|
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
"""Support framework for the executable documentation samples (doctests).
|
|
2
|
+
|
|
3
|
+
This module exposes a single declarative entry point, :func:`make_doc_env`,
|
|
4
|
+
which takes a :class:`DocEnvSpec` parameter object and returns a mapping of
|
|
5
|
+
names to inject into a document's doctest globals. It is responsible for all
|
|
6
|
+
the boilerplate the samples themselves should not have to show:
|
|
7
|
+
|
|
8
|
+
* an isolated working directory, so literal ``open('document.pdf', 'rb')``
|
|
9
|
+
calls in the samples resolve against real files;
|
|
10
|
+
* materialised input files (sample PDFs) and signer key material (PEM and
|
|
11
|
+
PKCS#12) written to the placeholder paths the samples reference;
|
|
12
|
+
* network mocking for timestamping and revocation info, so samples that talk
|
|
13
|
+
to ``http://tsa.example.com`` or fetch OCSP/CRLs simply work;
|
|
14
|
+
* a bundle of injected helper symbols (test signers, timestampers and the
|
|
15
|
+
stand-in "remote service" callables used by the interrupted-signing
|
|
16
|
+
examples).
|
|
17
|
+
|
|
18
|
+
Everything is built on top of the existing test utilities
|
|
19
|
+
(:mod:`pyhanko_testing_commons.test_utils.signing_commons` and
|
|
20
|
+
:mod:`pyhanko_testing_commons.test_data.samples`), so the certomancer PKI,
|
|
21
|
+
canonical sample PDFs and key material are reused verbatim.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import asyncio
|
|
25
|
+
import enum
|
|
26
|
+
import os
|
|
27
|
+
import tempfile
|
|
28
|
+
from collections.abc import Awaitable, Callable, Mapping
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from datetime import datetime, timedelta, timezone
|
|
31
|
+
from io import BytesIO
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from typing import (
|
|
34
|
+
Any,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
import aiohttp
|
|
38
|
+
import aiohttp.web
|
|
39
|
+
import tzlocal
|
|
40
|
+
from asn1crypto import pem, tsp
|
|
41
|
+
from certomancer import PKIArchitecture
|
|
42
|
+
from certomancer.integrations.aiohttp_illusionist import AsyncIllusionist
|
|
43
|
+
from certomancer.registry import (
|
|
44
|
+
ArchLabel,
|
|
45
|
+
CertLabel,
|
|
46
|
+
EntityLabel,
|
|
47
|
+
KeyLabel,
|
|
48
|
+
ServiceLabel,
|
|
49
|
+
)
|
|
50
|
+
from cryptography.hazmat.primitives import serialization
|
|
51
|
+
from freezegun import freeze_time
|
|
52
|
+
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
|
|
53
|
+
from pyhanko.sign import fields, signers, timestamps
|
|
54
|
+
from pyhanko.sign.signers.pdf_cms import ExternalSigner, SimpleSigner
|
|
55
|
+
from pyhanko_certvalidator import ValidationContext
|
|
56
|
+
from pyhanko_certvalidator.registry import SimpleCertificateStore
|
|
57
|
+
|
|
58
|
+
from pyhanko_testing_commons.test_data import samples
|
|
59
|
+
from pyhanko_testing_commons.test_data.certomancer_trust_lists import (
|
|
60
|
+
certomancer_pki_as_trusted_list,
|
|
61
|
+
)
|
|
62
|
+
from pyhanko_testing_commons.test_utils import signing_commons
|
|
63
|
+
from pyhanko_testing_commons.test_utils.live_http import live_pki_services
|
|
64
|
+
|
|
65
|
+
__all__ = [
|
|
66
|
+
'EXAMPLE_DOMAIN',
|
|
67
|
+
'FREEZE_DT',
|
|
68
|
+
'DocEnv',
|
|
69
|
+
'DocEnvSpec',
|
|
70
|
+
'SignatureProfile',
|
|
71
|
+
'SignedDocSpec',
|
|
72
|
+
'SignerProvisioning',
|
|
73
|
+
'SignerSpec',
|
|
74
|
+
'TimestampSpec',
|
|
75
|
+
'TrustListSpec',
|
|
76
|
+
'TrustSpec',
|
|
77
|
+
'make_doc_env',
|
|
78
|
+
'run_with_seeded_lotl',
|
|
79
|
+
'seed_lotl_cache',
|
|
80
|
+
'teardown_doc_env',
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
#: Single canonical domain from which every example URL is derived. The
|
|
85
|
+
#: samples display URLs under this domain, and the network mocks key off it.
|
|
86
|
+
EXAMPLE_DOMAIN = 'pyhanko.tests'
|
|
87
|
+
|
|
88
|
+
#: Fixed point in time at which the doctests run. Chosen to fall within the
|
|
89
|
+
#: validity window of the certomancer ``testing-ca`` material.
|
|
90
|
+
FREEZE_DT = datetime(2020, 8, 1, tzinfo=timezone.utc).astimezone(
|
|
91
|
+
tz=tzlocal.get_localzone()
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
#: Point in time at which samples that consume the *real* bundled EU trusted
|
|
95
|
+
#: lists run. Those are signed by actual EU trust service providers, whose
|
|
96
|
+
#: certificates postdate :data:`FREEZE_DT` by years; this instant sits within
|
|
97
|
+
#: their validity window instead. Refreshing the bundled lists may require
|
|
98
|
+
#: moving it.
|
|
99
|
+
REAL_TL_DT = datetime(2026, 3, 1, tzinfo=timezone.utc).astimezone(
|
|
100
|
+
tz=tzlocal.get_localzone()
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class SignerProvisioning(enum.Enum):
|
|
105
|
+
"""Ways in which signer key material is made available to a sample."""
|
|
106
|
+
|
|
107
|
+
PEM = 'pem'
|
|
108
|
+
"""Separate ``key.pem`` + ``cert.pem`` (+ a CA chain file)."""
|
|
109
|
+
|
|
110
|
+
PKCS12 = 'pkcs12'
|
|
111
|
+
"""A single bundled ``.pfx`` file."""
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass(frozen=True)
|
|
115
|
+
class SignerSpec:
|
|
116
|
+
"""Describes the signer key material to materialise on disk."""
|
|
117
|
+
|
|
118
|
+
cert: CertLabel = CertLabel('signer1')
|
|
119
|
+
"""The certomancer certificate (and matching key) to provision."""
|
|
120
|
+
|
|
121
|
+
provisioning: SignerProvisioning = SignerProvisioning.PEM
|
|
122
|
+
"""How the key material is laid out on disk."""
|
|
123
|
+
|
|
124
|
+
key_passphrase: bytes = b'secret'
|
|
125
|
+
"""Passphrase protecting the private key / PKCS#12 bundle."""
|
|
126
|
+
|
|
127
|
+
key_path: str = 'path/to/signer/key.pem'
|
|
128
|
+
"""Destination for the PEM-encoded private key."""
|
|
129
|
+
|
|
130
|
+
cert_path: str = 'path/to/signer/cert.pem'
|
|
131
|
+
"""Destination for the PEM-encoded signer certificate."""
|
|
132
|
+
|
|
133
|
+
chain_path: str | None = 'path/to/relevant/certs.pem'
|
|
134
|
+
"""Destination for the PEM-encoded CA chain, or ``None`` to skip it."""
|
|
135
|
+
|
|
136
|
+
pfx_path: str = 'signer.pfx'
|
|
137
|
+
"""Destination for the PKCS#12 bundle."""
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@dataclass(frozen=True)
|
|
141
|
+
class TrustSpec:
|
|
142
|
+
"""Chain-of-trust configuration for validation samples."""
|
|
143
|
+
|
|
144
|
+
trust_root: CertLabel = CertLabel('root')
|
|
145
|
+
"""Trust anchor used to validate signatures produced in the sample."""
|
|
146
|
+
|
|
147
|
+
fetch_revocation: bool = False
|
|
148
|
+
"""Whether to register OCSP/CRL responders for live revocation fetching."""
|
|
149
|
+
|
|
150
|
+
cert_path: str | None = 'path/to/certfile'
|
|
151
|
+
"""Destination for the PEM-encoded trust root, or ``None`` to skip it.
|
|
152
|
+
Samples that call ``load_cert_from_pemder('path/to/certfile')`` read it."""
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass(frozen=True)
|
|
156
|
+
class TrustListSpec:
|
|
157
|
+
"""ETSI trusted-list configuration for qualified-signature samples.
|
|
158
|
+
|
|
159
|
+
When present, a signed trusted list covering the architecture's PKI is
|
|
160
|
+
written to disk so a sample can build a
|
|
161
|
+
:class:`~pyhanko.sign.validation.qualified.tsp.TSPRegistry` from it, exactly
|
|
162
|
+
as it would from a real national trusted list.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
tlso_entity: EntityLabel = EntityLabel('root')
|
|
166
|
+
"""Entity in the test PKI that acts as trusted-list scheme operator and
|
|
167
|
+
signs the list."""
|
|
168
|
+
|
|
169
|
+
xml_path: str = 'trusted-list.xml'
|
|
170
|
+
"""Destination for the signed trusted-list XML."""
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@dataclass(frozen=True)
|
|
174
|
+
class TimestampSpec:
|
|
175
|
+
"""Timestamping configuration for samples that embed timestamp tokens."""
|
|
176
|
+
|
|
177
|
+
service: ServiceLabel = ServiceLabel('tsa')
|
|
178
|
+
"""Which TSA in the test PKI backs the mocked :data:`TSA_URL`."""
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class SignatureProfile(enum.Enum):
|
|
182
|
+
"""Profile of a pre-signed document materialised for validation samples."""
|
|
183
|
+
|
|
184
|
+
PLAIN = 'plain'
|
|
185
|
+
"""A single, plain approval signature."""
|
|
186
|
+
|
|
187
|
+
PADES = 'pades'
|
|
188
|
+
"""A PAdES baseline (B-B) signature, without embedded revocation info or a
|
|
189
|
+
timestamp (suitable for qualified-signature samples that fetch revocation
|
|
190
|
+
info live)."""
|
|
191
|
+
|
|
192
|
+
PADES_LTA = 'pades_lta'
|
|
193
|
+
"""A PAdES B-LTA signature with embedded revocation info and a document
|
|
194
|
+
timestamp (suitable for long-term validation samples)."""
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass(frozen=True)
|
|
198
|
+
class SignedDocSpec:
|
|
199
|
+
"""Describes a pre-signed document to materialise for validation samples."""
|
|
200
|
+
|
|
201
|
+
path: str = 'document.pdf'
|
|
202
|
+
"""Destination for the signed document."""
|
|
203
|
+
|
|
204
|
+
base_file: str = 'MINIMAL_ONE_FIELD'
|
|
205
|
+
"""Source identifier for the unsigned base document (see
|
|
206
|
+
:func:`_resolve_source`); must contain an empty signature field."""
|
|
207
|
+
|
|
208
|
+
field_name: str = 'Sig1'
|
|
209
|
+
"""Name of the signature field to fill."""
|
|
210
|
+
|
|
211
|
+
profile: SignatureProfile = SignatureProfile.PLAIN
|
|
212
|
+
"""Which :class:`SignatureProfile` to produce."""
|
|
213
|
+
|
|
214
|
+
signer_cert: CertLabel = CertLabel('signer1')
|
|
215
|
+
"""Certificate (within the architecture) of the signer."""
|
|
216
|
+
|
|
217
|
+
signer_key: KeyLabel = KeyLabel('signer1')
|
|
218
|
+
"""Private key (within the architecture) used to sign."""
|
|
219
|
+
|
|
220
|
+
signer_chain: tuple[CertLabel, ...] = (
|
|
221
|
+
CertLabel('root'),
|
|
222
|
+
CertLabel('interm'),
|
|
223
|
+
)
|
|
224
|
+
"""CA certificates to embed alongside the signature."""
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@dataclass(frozen=True)
|
|
228
|
+
class DocEnvSpec:
|
|
229
|
+
"""Declarative description of the environment a document's samples need.
|
|
230
|
+
|
|
231
|
+
Every field has a sane default, so ``DocEnvSpec()`` yields an isolated
|
|
232
|
+
working directory containing ``document.pdf`` plus PEM signer material for
|
|
233
|
+
the RSA ``testing-ca`` architecture.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
certomancer_config: str = samples.CERTOMANCER_CONFIG_PATH
|
|
237
|
+
"""Path to the certomancer configuration to load architectures from."""
|
|
238
|
+
|
|
239
|
+
arch: ArchLabel = ArchLabel('testing-ca')
|
|
240
|
+
"""Architecture within that configuration to wire up."""
|
|
241
|
+
|
|
242
|
+
files: Mapping[str, str] = field(
|
|
243
|
+
default_factory=lambda: {'document.pdf': 'MINIMAL'}
|
|
244
|
+
)
|
|
245
|
+
"""Maps destination file names to a source identifier (see
|
|
246
|
+
:func:`_resolve_source`)."""
|
|
247
|
+
|
|
248
|
+
signers: tuple[SignerSpec, ...] = (SignerSpec(),)
|
|
249
|
+
"""Signer key material to provision. A document may need several layouts
|
|
250
|
+
(e.g. both PEM files and a PKCS#12 bundle); pass an empty tuple for none."""
|
|
251
|
+
|
|
252
|
+
signed_documents: tuple[SignedDocSpec, ...] = ()
|
|
253
|
+
"""Pre-signed documents to materialise (for validation samples)."""
|
|
254
|
+
|
|
255
|
+
trust: TrustSpec | None = None
|
|
256
|
+
"""Chain-of-trust configuration, or ``None``."""
|
|
257
|
+
|
|
258
|
+
trust_list: TrustListSpec | None = None
|
|
259
|
+
"""ETSI trusted-list configuration for qualified-signature samples, or
|
|
260
|
+
``None``."""
|
|
261
|
+
|
|
262
|
+
timestamping: TimestampSpec = TimestampSpec()
|
|
263
|
+
"""Timestamping configuration, or ``None``."""
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# Logical source names that resolve to asset files shipped with the test data,
|
|
267
|
+
# in addition to the byte constants exposed by the samples module.
|
|
268
|
+
_ASSET_SOURCES = {
|
|
269
|
+
'NotoSans-Regular.ttf': samples.PDF_DATA_DIR
|
|
270
|
+
+ '/../fonts/NotoSans-Regular.ttf',
|
|
271
|
+
'stamp.png': samples.PDF_DATA_DIR + '/../img/stamp.png',
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _resolve_source(name: str) -> bytes:
|
|
276
|
+
"""Resolve a ``files`` source identifier to raw bytes.
|
|
277
|
+
|
|
278
|
+
The identifier is looked up first as a ``bytes`` constant on the samples
|
|
279
|
+
module (e.g. ``'MINIMAL'``), then as a named asset file.
|
|
280
|
+
"""
|
|
281
|
+
value = getattr(samples, name, None)
|
|
282
|
+
if isinstance(value, bytes):
|
|
283
|
+
return value
|
|
284
|
+
if name in _ASSET_SOURCES:
|
|
285
|
+
return samples.read_all(_ASSET_SOURCES[name])
|
|
286
|
+
raise KeyError(f"Unknown doctest file source: {name!r}")
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@dataclass
|
|
290
|
+
class DocEnv:
|
|
291
|
+
"""Live handle on a materialised doctest environment.
|
|
292
|
+
|
|
293
|
+
Held onto by the generated globals so that :func:`teardown_doc_env` can
|
|
294
|
+
restore the working directory and tear down the active mocks.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
workdir: str
|
|
298
|
+
prev_cwd: str
|
|
299
|
+
globals: dict[str, Any]
|
|
300
|
+
_closers: list[Any]
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _write_file(path: str, data: bytes) -> None:
|
|
304
|
+
parent = os.path.dirname(path)
|
|
305
|
+
if parent:
|
|
306
|
+
os.makedirs(parent, exist_ok=True)
|
|
307
|
+
with open(path, 'wb') as outf:
|
|
308
|
+
outf.write(data)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _provision_signer(arch: PKIArchitecture, spec: SignerSpec) -> None:
|
|
312
|
+
cert = arch.get_cert(spec.cert)
|
|
313
|
+
if spec.provisioning == SignerProvisioning.PKCS12:
|
|
314
|
+
p12 = arch.package_pkcs12(spec.cert, password=spec.key_passphrase)
|
|
315
|
+
_write_file(spec.pfx_path, p12)
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
key_info = arch.key_set.get_private_key(KeyLabel(str(spec.cert)))
|
|
319
|
+
private_key = serialization.load_der_private_key(
|
|
320
|
+
key_info.dump(), password=None
|
|
321
|
+
)
|
|
322
|
+
key_pem = private_key.private_bytes(
|
|
323
|
+
encoding=serialization.Encoding.PEM,
|
|
324
|
+
format=serialization.PrivateFormat.PKCS8,
|
|
325
|
+
encryption_algorithm=serialization.BestAvailableEncryption(
|
|
326
|
+
spec.key_passphrase
|
|
327
|
+
),
|
|
328
|
+
)
|
|
329
|
+
_write_file(spec.key_path, key_pem)
|
|
330
|
+
_write_file(spec.cert_path, pem.armor('CERTIFICATE', cert.dump()))
|
|
331
|
+
if spec.chain_path is not None:
|
|
332
|
+
chain = b''.join(
|
|
333
|
+
pem.armor('CERTIFICATE', arch.get_cert(CertLabel(label)).dump())
|
|
334
|
+
for label in ('root', 'interm')
|
|
335
|
+
)
|
|
336
|
+
_write_file(spec.chain_path, chain)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _build_signer(arch: PKIArchitecture, spec: SignedDocSpec) -> SimpleSigner:
|
|
340
|
+
return SimpleSigner(
|
|
341
|
+
signing_cert=arch.get_cert(spec.signer_cert),
|
|
342
|
+
signing_key=arch.key_set.get_private_key(spec.signer_key),
|
|
343
|
+
cert_registry=SimpleCertificateStore.from_certs(
|
|
344
|
+
arch.get_cert(label) for label in spec.signer_chain
|
|
345
|
+
),
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def _generate_signed_doc(
|
|
350
|
+
arch: PKIArchitecture, spec: SignedDocSpec, ts_spec: TimestampSpec | None
|
|
351
|
+
) -> None:
|
|
352
|
+
"""Produce a signed PDF and write it to ``spec.path``.
|
|
353
|
+
|
|
354
|
+
Must be called while the timestamp/revocation mocks and ``freeze_time`` are
|
|
355
|
+
active, since the B-LTA profile fetches revocation info and a timestamp.
|
|
356
|
+
"""
|
|
357
|
+
base = _resolve_source(spec.base_file)
|
|
358
|
+
writer = IncrementalPdfFileWriter(BytesIO(base))
|
|
359
|
+
signer = _build_signer(arch, spec)
|
|
360
|
+
if spec.profile == SignatureProfile.PADES_LTA:
|
|
361
|
+
if not ts_spec:
|
|
362
|
+
raise ValueError("ts_spec must not be None")
|
|
363
|
+
root = arch.get_cert(CertLabel('root'))
|
|
364
|
+
meta = signers.PdfSignatureMetadata(
|
|
365
|
+
field_name=spec.field_name,
|
|
366
|
+
md_algorithm='sha256',
|
|
367
|
+
subfilter=fields.SigSeedSubFilter.PADES,
|
|
368
|
+
validation_context=ValidationContext(
|
|
369
|
+
trust_roots=[root], allow_fetching=True, other_certs=[]
|
|
370
|
+
),
|
|
371
|
+
embed_validation_info=True,
|
|
372
|
+
use_pades_lta=True,
|
|
373
|
+
)
|
|
374
|
+
out = signers.sign_pdf(
|
|
375
|
+
writer,
|
|
376
|
+
meta,
|
|
377
|
+
signer=signer,
|
|
378
|
+
timestamper=timestamps.HTTPTimeStamper(
|
|
379
|
+
arch.service_registry.get_tsa_info(ts_spec.service).url
|
|
380
|
+
),
|
|
381
|
+
existing_fields_only=True,
|
|
382
|
+
)
|
|
383
|
+
elif spec.profile == SignatureProfile.PADES:
|
|
384
|
+
out = signers.sign_pdf(
|
|
385
|
+
writer,
|
|
386
|
+
signers.PdfSignatureMetadata(
|
|
387
|
+
field_name=spec.field_name,
|
|
388
|
+
subfilter=fields.SigSeedSubFilter.PADES,
|
|
389
|
+
),
|
|
390
|
+
signer=signer,
|
|
391
|
+
existing_fields_only=True,
|
|
392
|
+
)
|
|
393
|
+
else:
|
|
394
|
+
out = signers.sign_pdf(
|
|
395
|
+
writer,
|
|
396
|
+
signers.PdfSignatureMetadata(field_name=spec.field_name),
|
|
397
|
+
signer=signer,
|
|
398
|
+
existing_fields_only=True,
|
|
399
|
+
)
|
|
400
|
+
_write_file(spec.path, out.getvalue())
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _tsa_callback(request_body: bytes) -> bytes:
|
|
404
|
+
req = tsp.TimeStampReq.load(request_body)
|
|
405
|
+
return signing_commons.DUMMY_TS.request_tsa_response(req=req).dump()
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _make_async_runner(
|
|
409
|
+
arch: PKIArchitecture,
|
|
410
|
+
) -> Callable[[Callable[[aiohttp.ClientSession], Awaitable[None]]], None]:
|
|
411
|
+
"""Build the ``run_async_signing`` helper injected into the doctest globals.
|
|
412
|
+
|
|
413
|
+
The ``aiohttp`` sample factors its logic into a coroutine that performs
|
|
414
|
+
PAdES-LTA signing given an :class:`aiohttp.ClientSession`. The helper runs
|
|
415
|
+
that coroutine against a certomancer
|
|
416
|
+
:class:`~certomancer.integrations.aiohttp_illusionist.AsyncIllusionist`,
|
|
417
|
+
whose served session transparently answers the OCSP/CRL fetches and the
|
|
418
|
+
timestamp request the sample makes, so the example runs end to end.
|
|
419
|
+
"""
|
|
420
|
+
illusionist = AsyncIllusionist(arch, at_time=FREEZE_DT)
|
|
421
|
+
|
|
422
|
+
def run_async_signing(
|
|
423
|
+
body: Callable[[aiohttp.ClientSession], Awaitable[None]],
|
|
424
|
+
) -> None:
|
|
425
|
+
async def _main() -> None:
|
|
426
|
+
app = illusionist.build_app()
|
|
427
|
+
async with illusionist.serving_session(app=app) as session:
|
|
428
|
+
await body(session)
|
|
429
|
+
|
|
430
|
+
asyncio.run(_main())
|
|
431
|
+
|
|
432
|
+
return run_async_signing
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def _make_standins(signer: SimpleSigner) -> dict:
|
|
436
|
+
"""Build the stand-in "remote service" helpers used by the
|
|
437
|
+
interrupted-signing examples.
|
|
438
|
+
|
|
439
|
+
These mimic an external signing service by routing the cryptographic work
|
|
440
|
+
through the in-process ``testing-ca`` key material, so the visible samples
|
|
441
|
+
can keep referring to opaque ``call_external_service`` /
|
|
442
|
+
``instantiate_external_signer`` helpers while still running end to end.
|
|
443
|
+
"""
|
|
444
|
+
|
|
445
|
+
cert = signer.signing_cert
|
|
446
|
+
registry = signer.cert_registry
|
|
447
|
+
|
|
448
|
+
# A non-signing ExternalSigner for size estimation / signed-attr assembly,
|
|
449
|
+
# standing in for a remote signer whose certificate is known up front.
|
|
450
|
+
ext_signer = ExternalSigner(
|
|
451
|
+
signing_cert=cert,
|
|
452
|
+
cert_registry=registry,
|
|
453
|
+
signature_value=bytes(256),
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
async def sign_remotely(signed_attrs_data: bytes) -> bytes:
|
|
457
|
+
# The "remote service" signs the prepared signed attributes with the
|
|
458
|
+
# real private key, yielding a value the caller can plug back in.
|
|
459
|
+
return await signer.async_sign_raw(signed_attrs_data, 'sha256')
|
|
460
|
+
|
|
461
|
+
def instantiate_external_signer(sig_value: bytes) -> ExternalSigner:
|
|
462
|
+
return ExternalSigner(
|
|
463
|
+
signing_cert=cert,
|
|
464
|
+
cert_registry=registry,
|
|
465
|
+
signature_value=sig_value,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
async def call_external_service(document_digest: bytes):
|
|
469
|
+
# Stand-in for a service that provisions a short-lived certificate and
|
|
470
|
+
# returns a complete CMS container given a document digest.
|
|
471
|
+
return await signer.async_sign(
|
|
472
|
+
document_digest,
|
|
473
|
+
digest_algorithm='sha256',
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
return {
|
|
477
|
+
'ext_signer': ext_signer,
|
|
478
|
+
'sign_remotely': sign_remotely,
|
|
479
|
+
'instantiate_external_signer': instantiate_external_signer,
|
|
480
|
+
'call_external_service': call_external_service,
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def make_doc_env(spec: DocEnvSpec = DocEnvSpec()) -> dict:
|
|
485
|
+
"""Materialise a doctest environment and return the doctest globals.
|
|
486
|
+
|
|
487
|
+
The returned mapping is meant to be fed to ``globals().update(...)`` in a
|
|
488
|
+
document's hidden ``.. testsetup:: *`` block. It contains the injected
|
|
489
|
+
helper symbols *and* a ``_doc_env`` handle consumed by
|
|
490
|
+
:func:`teardown_doc_env`.
|
|
491
|
+
|
|
492
|
+
:param spec:
|
|
493
|
+
Declarative description of the environment; see :class:`DocEnvSpec`.
|
|
494
|
+
:return:
|
|
495
|
+
A mapping of names to inject into the doctest globals.
|
|
496
|
+
"""
|
|
497
|
+
|
|
498
|
+
arch = samples.CERTOMANCER.get_pki_arch(spec.arch)
|
|
499
|
+
|
|
500
|
+
prev_cwd = os.getcwd()
|
|
501
|
+
workdir = tempfile.mkdtemp(prefix='pyhanko-doctest-')
|
|
502
|
+
os.chdir(workdir)
|
|
503
|
+
|
|
504
|
+
closers: list[Any] = []
|
|
505
|
+
try:
|
|
506
|
+
freezer = freeze_time(FREEZE_DT)
|
|
507
|
+
freezer.start()
|
|
508
|
+
closers.append(freezer.stop)
|
|
509
|
+
|
|
510
|
+
needs_pades = any(
|
|
511
|
+
doc.profile == SignatureProfile.PADES_LTA
|
|
512
|
+
for doc in spec.signed_documents
|
|
513
|
+
)
|
|
514
|
+
register_services = (
|
|
515
|
+
spec.trust is not None and spec.trust.fetch_revocation
|
|
516
|
+
) or needs_pades
|
|
517
|
+
|
|
518
|
+
services_cm = live_pki_services()
|
|
519
|
+
services = services_cm.__enter__()
|
|
520
|
+
closers.append(lambda: services_cm.__exit__(None, None, None))
|
|
521
|
+
services.post(
|
|
522
|
+
arch.service_registry.get_tsa_info(spec.timestamping.service).url,
|
|
523
|
+
content=_tsa_callback,
|
|
524
|
+
content_type='application/timestamp-reply',
|
|
525
|
+
)
|
|
526
|
+
if register_services:
|
|
527
|
+
services.register(arch)
|
|
528
|
+
|
|
529
|
+
for dest, source in spec.files.items():
|
|
530
|
+
_write_file(dest, _resolve_source(source))
|
|
531
|
+
|
|
532
|
+
for signer_spec in spec.signers:
|
|
533
|
+
_provision_signer(arch, signer_spec)
|
|
534
|
+
|
|
535
|
+
if spec.trust is not None and spec.trust.cert_path is not None:
|
|
536
|
+
trust_cert = arch.get_cert(spec.trust.trust_root)
|
|
537
|
+
_write_file(
|
|
538
|
+
spec.trust.cert_path,
|
|
539
|
+
pem.armor('CERTIFICATE', trust_cert.dump()),
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
if spec.trust_list is not None:
|
|
543
|
+
tl_xml = certomancer_pki_as_trusted_list(
|
|
544
|
+
arch, spec.trust_list.tlso_entity
|
|
545
|
+
)
|
|
546
|
+
_write_file(spec.trust_list.xml_path, tl_xml.encode('utf-8'))
|
|
547
|
+
|
|
548
|
+
for doc_spec in spec.signed_documents:
|
|
549
|
+
_generate_signed_doc(arch, doc_spec, spec.timestamping)
|
|
550
|
+
|
|
551
|
+
injected: dict[str, Any] = {
|
|
552
|
+
'run_async_signing': _make_async_runner(arch),
|
|
553
|
+
'run_with_seeded_lotl': run_with_seeded_lotl,
|
|
554
|
+
'TSA_URL': arch.service_registry.get_tsa_info(
|
|
555
|
+
spec.timestamping.service
|
|
556
|
+
).url,
|
|
557
|
+
}
|
|
558
|
+
injected.update(_make_standins(signing_commons.FROM_CA))
|
|
559
|
+
except Exception:
|
|
560
|
+
# Make sure a partially constructed environment doesn't leak the cwd
|
|
561
|
+
# change or any started mocks.
|
|
562
|
+
for closer in reversed(closers):
|
|
563
|
+
closer()
|
|
564
|
+
os.chdir(prev_cwd)
|
|
565
|
+
raise
|
|
566
|
+
|
|
567
|
+
env = DocEnv(
|
|
568
|
+
workdir=workdir,
|
|
569
|
+
prev_cwd=prev_cwd,
|
|
570
|
+
globals=injected,
|
|
571
|
+
_closers=closers,
|
|
572
|
+
)
|
|
573
|
+
injected['_doc_env'] = env
|
|
574
|
+
return injected
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def teardown_doc_env(env: DocEnv) -> None:
|
|
578
|
+
"""Tear down an environment produced by :func:`make_doc_env`.
|
|
579
|
+
|
|
580
|
+
Restores the previous working directory and stops the timestamp/revocation
|
|
581
|
+
mocks. Safe to call once per document in a ``.. testcleanup::`` block.
|
|
582
|
+
|
|
583
|
+
:param env:
|
|
584
|
+
The :class:`DocEnv` handle (typically referenced as ``_doc_env`` in the
|
|
585
|
+
doctest globals).
|
|
586
|
+
"""
|
|
587
|
+
for closer in reversed(env._closers):
|
|
588
|
+
closer()
|
|
589
|
+
env._closers.clear()
|
|
590
|
+
os.chdir(env.prev_cwd)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def seed_lotl_cache(cache_dir: str | os.PathLike) -> str:
|
|
594
|
+
"""Pre-seed a :class:`FileSystemTLCache` directory with the bundled EU
|
|
595
|
+
list-of-the-lists and the Belgian national trusted list.
|
|
596
|
+
|
|
597
|
+
This lets the live-bootstrap sample in the qualified-validation guide run
|
|
598
|
+
without touching the network: every download
|
|
599
|
+
:func:`~.pyhanko.sign.validation.qualified.eutl_fetch.lotl_to_registry`
|
|
600
|
+
would otherwise perform becomes a cache hit. Restricting the sample to a
|
|
601
|
+
single member state (``only_territories={'be'}``) keeps it fast and means
|
|
602
|
+
only the Belgian list has to be seeded alongside the LOTL itself.
|
|
603
|
+
|
|
604
|
+
:param cache_dir:
|
|
605
|
+
Directory to populate; created if it does not yet exist.
|
|
606
|
+
:return:
|
|
607
|
+
The cache directory as a string, handy for feeding straight back into
|
|
608
|
+
the sample.
|
|
609
|
+
"""
|
|
610
|
+
from pyhanko.sign.validation.qualified.eutl_fetch import (
|
|
611
|
+
EU_LOTL_LOCATION,
|
|
612
|
+
FileSystemTLCache,
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
tl_dir = Path(samples.TEST_DIR) / 'data' / 'tl'
|
|
616
|
+
cache = FileSystemTLCache(
|
|
617
|
+
Path(cache_dir), expire_after=timedelta(days=3650)
|
|
618
|
+
)
|
|
619
|
+
cache[EU_LOTL_LOCATION] = (tl_dir / 'eu-lotl.xml').read_text(
|
|
620
|
+
encoding='utf8'
|
|
621
|
+
)
|
|
622
|
+
# The Belgian list's location as advertised in the bundled LOTL.
|
|
623
|
+
cache['https://tsl.belgium.be/tsl-be-v6.xml'] = (
|
|
624
|
+
tl_dir / 'tsl-be-v6.xml'
|
|
625
|
+
).read_text(encoding='utf8')
|
|
626
|
+
return str(cache_dir)
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def run_with_seeded_lotl(
|
|
630
|
+
body: Callable[[str], Awaitable[Any]], cache_dir: str = 'lotl-cache'
|
|
631
|
+
) -> Any:
|
|
632
|
+
"""Run a coroutine that bootstraps from the EU list-of-the-lists.
|
|
633
|
+
|
|
634
|
+
Seeds ``cache_dir`` through :func:`seed_lotl_cache` and runs ``body``
|
|
635
|
+
against it at :data:`REAL_TL_DT`, overriding the document's usual frozen
|
|
636
|
+
clock for the duration.
|
|
637
|
+
|
|
638
|
+
:param body:
|
|
639
|
+
Callable taking the cache directory and returning the coroutine to run.
|
|
640
|
+
:param cache_dir:
|
|
641
|
+
Directory to seed and hand to ``body``.
|
|
642
|
+
:return:
|
|
643
|
+
Whatever the coroutine returns.
|
|
644
|
+
"""
|
|
645
|
+
with freeze_time(REAL_TL_DT):
|
|
646
|
+
seed_lotl_cache(cache_dir)
|
|
647
|
+
return asyncio.run(body(cache_dir))
|
|
@@ -409,6 +409,13 @@ pki-architectures:
|
|
|
409
409
|
testing-ca-ed25519:
|
|
410
410
|
template: testing-ca
|
|
411
411
|
keyset: testing-ca-ed25519
|
|
412
|
+
certs:
|
|
413
|
+
signer1-indefinite:
|
|
414
|
+
subject: signer1
|
|
415
|
+
template: signer1
|
|
416
|
+
validity:
|
|
417
|
+
valid-from: "2020-01-01T00:00:00+0000"
|
|
418
|
+
valid-to: "9999-12-31T23:59:59+0000"
|
|
412
419
|
services:
|
|
413
420
|
time-stamping:
|
|
414
421
|
tsa:
|