MatthiasValvekens / pyHanko

pyHanko: sign and stamp PDF files
MIT License
483 stars 71 forks source link

[pyhanko-certvalidator] Ability to skip nonce validation in OCSP response #321

Closed sagarvora closed 9 months ago

sagarvora commented 11 months ago

Issue

One of the CAs I'm working with currently has an incorrect implementation of the nonce extension for OCSP. They are responding with the nonce value, but it's always the same. I suspect this might be because the response is cached on the CA's side. This leads to OCSPValidationError being raised in certvalidator. There are also some issues related to this in the wbond/certvalidator repo.

Proposed Solution

Add an option in the ValidationContext to disable nonce extension entirely. If this sounds okay, I can make a Pull Request for the same :)

sagarvora commented 11 months ago

Some additional notes:

MatthiasValvekens commented 11 months ago

EDIT: oops, clicked the submit button a bit too early

but this is always True when the fetchers are initialised.

Yes, that's by design (as it is intended to the default). You can, however, initialise (and resource-manage) your own fetchers and pass those to the validation context. Does that work for you?

This error currently causes the whole PDF signing process to fail instead of falling back to CRL fetching.

That's definitely a bug. Can you post a sample stack trace here?

sagarvora commented 11 months ago

Yes, that's by design (as it is intended to the default). You can, however, initialise (and resource-manage) your own fetchers and pass those to the validation context. Does that work for you?

Thanks for the idea. This worked for me:

from pyhanko_certvalidator.fetchers import default_fetcher_backend

fetchers = default_fetcher_backend().get_fetchers()
fetchers.ocsp_fetcher.request_nonces = False
validation_context = ValidationContext(allow_fetching=True, fetchers=fetchers)

That's definitely a bug. Can you post a sample stack trace here?

Traceback (most recent call last):
  File "certvalidator/pyhanko_certvalidator/fetchers/common_utils.py", line 237, in queue_fetch_task
    wait_event: asyncio.Event = running_jobs[tag]
KeyError: (b'\xef\x9 --- trimmed ---'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "pyHanko/pyhanko/cli/runtime.py", line 50, in pyhanko_exception_manager
    yield
  File "pyHanko/pyhanko/cli/commands/signing/plugin.py", line 132, in _callback
    _callback_logic(plugin, infile, outfile, **kwargs)
  File "pyHanko/pyhanko/cli/commands/signing/plugin.py", line 111, in _callback_logic
    result = PdfSigner(
  File "pyHanko/pyhanko/sign/signers/pdf_signer.py", line 1423, in sign_pdf
    result = asyncio.run(
  File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "pyHanko/pyhanko/sign/signers/pdf_signer.py", line 1485, in async_sign_pdf
    validation_info = await signing_session.perform_presign_validation(
  File "pyHanko/pyhanko/sign/signers/pdf_signer.py", line 1654, in perform_presign_validation
    signer_path = await self._perform_presign_signer_validation(
  File "pyHanko/pyhanko/sign/signers/pdf_signer.py", line 1753, in _perform_presign_signer_validation
    signer_cert_validation_path = await validator.async_validate_usage(
  File "certvalidator/pyhanko_certvalidator/__init__.py", line 269, in async_validate_usage
    validated_path = await self.async_validate_path()
  File "certvalidator/pyhanko_certvalidator/__init__.py", line 136, in async_validate_path
    self._path = candidate_path = await find_valid_path(
  File "certvalidator/pyhanko_certvalidator/__init__.py", line 36, in find_valid_path
    await async_validate_path(
  File "certvalidator/pyhanko_certvalidator/validate.py", line 145, in async_validate_path
    return await intl_validate_path(
  File "certvalidator/pyhanko_certvalidator/validate.py", line 1111, in intl_validate_path
    await _check_revocation(
  File "certvalidator/pyhanko_certvalidator/validate.py", line 1298, in _check_revocation
    await verify_ocsp_response(
  File "certvalidator/pyhanko_certvalidator/revinfo/validate_ocsp.py", line 547, in verify_ocsp_response
    await validation_context.revinfo_manager.async_retrieve_ocsps(
  File "certvalidator/pyhanko_certvalidator/revinfo/manager.py", line 214, in async_retrieve_ocsps
    ocsp_response_data = await fetchers.ocsp_fetcher.fetch(
  File "certvalidator/pyhanko_certvalidator/fetchers/requests_fetchers/ocsp_client.py", line 44, in fetch
    return await self._perform_fetch(
  File "certvalidator/pyhanko_certvalidator/fetchers/requests_fetchers/util.py", line 36, in _perform_fetch
    return await queue_fetch_task(
  File "certvalidator/pyhanko_certvalidator/fetchers/common_utils.py", line 262, in queue_fetch_task
    return _return_or_raise(result)
  File "certvalidator/pyhanko_certvalidator/fetchers/common_utils.py", line 267, in _return_or_raise
    raise result
  File "certvalidator/pyhanko_certvalidator/fetchers/common_utils.py", line 251, in queue_fetch_task
    result = await async_fun()
  File "certvalidator/pyhanko_certvalidator/fetchers/requests_fetchers/ocsp_client.py", line 89, in _fetch
    ocsp_response = await ocsp_job_get_earliest(
  File "certvalidator/pyhanko_certvalidator/fetchers/common_utils.py", line 303, in ocsp_job_get_earliest
    ocsp_resp = await ocsp_job
  File "certvalidator/pyhanko_certvalidator/fetchers/requests_fetchers/ocsp_client.py", line 57, in _fetch_single
    return process_ocsp_response_data(
  File "certvalidator/pyhanko_certvalidator/fetchers/common_utils.py", line 205, in process_ocsp_response_data
    raise errors.OCSPValidationError(
pyhanko_certvalidator.errors.OCSPValidationError: Unable to verify OCSP response since the request and response nonces do not match
Error: Generic processing error.