Skip to content

Commit

Permalink
Regression tests for nonstrict post-signing ops
Browse files Browse the repository at this point in the history
See #466
  • Loading branch information
MatthiasValvekens committed Nov 11, 2024
1 parent ffbb3ff commit b038ee5
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 3 deletions.
22 changes: 19 additions & 3 deletions pyhanko_tests/cli_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from freezegun import freeze_time
from pyhanko_certvalidator import ValidationContext

from pyhanko.pdf_utils.misc import PdfStrictReadError
from pyhanko.pdf_utils.reader import PdfFileReader
from pyhanko.sign.validation import (
RevocationInfoValidationType,
Expand Down Expand Up @@ -131,12 +132,12 @@ def _write_config(config: dict, fname: str = 'pyhanko.yml'):
logger = logging.getLogger(__name__)


def _validate_last_sig_in(arch: PKIArchitecture, pdf_file):
def _validate_last_sig_in(arch: PKIArchitecture, pdf_file, *, strict):
vc_kwargs = dict(trust_roots=[arch.get_cert(CertLabel('root'))])
vc = ValidationContext(**vc_kwargs, allow_fetching=True)
with open(pdf_file, 'rb') as result:
logger.info(f"Validating last signature in {pdf_file}...")
r = PdfFileReader(result)
r = PdfFileReader(result, strict=strict)
# Little hack for the tests with encrypted files
if r.security_handler is not None:
r.decrypt("ownersecret")
Expand All @@ -163,5 +164,20 @@ def _validate_last_sig_in(arch: PKIArchitecture, pdf_file):
@pytest.fixture
def post_validate(pki_arch):
yield
input_passes_strict = True
if os.path.isfile(INPUT_PATH):
try:
with open(INPUT_PATH, 'rb') as inf:
PdfFileReader(inf)
except PdfStrictReadError:
logger.info(
f"Input file {INPUT_PATH} can't be opened in strict mode, "
f"will validate output {SIGNED_OUTPUT_PATH} in "
f"nonstrict mode as well"
)
input_passes_strict = False

if os.path.isfile(SIGNED_OUTPUT_PATH):
_validate_last_sig_in(pki_arch, SIGNED_OUTPUT_PATH)
_validate_last_sig_in(
pki_arch, SIGNED_OUTPUT_PATH, strict=input_passes_strict
)
44 changes: 44 additions & 0 deletions pyhanko_tests/cli_tests/test_cli_signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,50 @@ def test_cli_pades_lta(
assert not result.exception, result.output


def test_cli_pades_lta_nonstrict(
pki_arch_name, timestamp_url, cli_runner, root_cert, p12_keys
):
if pki_arch_name == 'ed448':
# FIXME deal with this bug on the Certomancer end
pytest.skip("ed448 timestamping in Certomancer doesn't work")
cfg = {
'pkcs12-setups': {
'test': {'pfx-file': p12_keys, 'pfx-passphrase': DUMMY_PASSPHRASE}
},
'validation-contexts': {
'test': {
'trust': root_cert,
}
},
}

_write_config(cfg)
with open(INPUT_PATH, 'wb') as inf:
inf.write(MINIMAL_SLIGHTLY_BROKEN)
result = cli_runner.invoke(
cli_root,
[
'sign',
'addsig',
'--field',
'Sig1',
'--no-strict-syntax',
'--validation-context',
'test',
'--with-validation-info',
'--use-pades-lta',
'--timestamp-url',
timestamp_url,
'pkcs12',
'--p12-setup',
'test',
INPUT_PATH,
SIGNED_OUTPUT_PATH,
],
)
assert not result.exception, result.output


def test_cli_addsig_pemder_encrypted_file(
cli_runner, cert_chain, user_key, monkeypatch
):
Expand Down
36 changes: 36 additions & 0 deletions pyhanko_tests/test_pades.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
RevocationCheckingRule,
)
from pyhanko_certvalidator.registry import SimpleCertificateStore
from samples import MINIMAL_SLIGHTLY_BROKEN

from pyhanko.pdf_utils.generic import pdf_name
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
Expand Down Expand Up @@ -89,6 +90,7 @@
SIMPLE_ECC_V_CONTEXT,
SIMPLE_V_CONTEXT,
TRUST_ROOTS,
async_val_trusted,
dummy_ocsp_vc,
live_ac_vcs,
live_testing_vc,
Expand Down Expand Up @@ -2380,3 +2382,37 @@ async def signed_attrs(self, *args, **kwargs):
# validate
ac_validation_context=(main_vc if pass_ac_vc else None),
)


@freeze_time('2020-11-01')
@pytest.mark.asyncio
async def test_interrupted_nonstrict_with_psi():
w = IncrementalPdfFileWriter(BytesIO(MINIMAL_SLIGHTLY_BROKEN), strict=False)
pdf_signer = signers.PdfSigner(
signers.PdfSignatureMetadata(
field_name='SigNew',
subfilter=PADES,
embed_validation_info=True,
validation_context=SIMPLE_V_CONTEXT(),
),
signer=FROM_CA,
timestamper=DUMMY_TS,
)
prep_digest, tbs_document, output = (
await pdf_signer.async_digest_doc_for_signing(w)
)
md_algorithm = tbs_document.md_algorithm
assert tbs_document.post_sign_instructions is not None

await PdfTBSDocument.async_finish_signing(
output,
prep_digest,
await FROM_CA.async_sign(
prep_digest.document_digest,
digest_algorithm=md_algorithm,
),
post_sign_instr=tbs_document.post_sign_instructions,
)

r = PdfFileReader(output, strict=False)
await async_val_trusted(r.embedded_signatures[0], extd=True)

0 comments on commit b038ee5

Please sign in to comment.