Coder Social home page Coder Social logo

pyhanko's People

Contributors

adilsitos avatar ccwienk avatar dependabot[bot] avatar dspinellis avatar eduperottoni avatar fornwall avatar fossabot avatar matthiasvalvekens avatar maycuatroi avatar peteris-zealid avatar robsco-git avatar sagarvora avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyhanko's Issues

Exception has occurred: ValueError not enough values to unpack (expected 1, got 0)

Hi:

I am trying to use pyhanko to perform a Pades-LTV signature using the spanish eID card. First I was trying with the CLI:

pyhanko sign addsig pkcs11 --lib /usr/lib64/pkcs11/opensc-pkcs11.so --token-label 'DNI electrónico (PIN1)' --cert-label CertFirmaDigital lorem_field.pdf lorem-f.pdf and get the following error, which I suppose is related to not being able to get the right certificate from the card:

Traceback (most recent call last):
File "/usr/local/lib64/python3.8/site-packages/pyhanko/cli.py", line 63, in pyhanko_exception_manager
yield
File "/usr/local/lib64/python3.8/site-packages/pyhanko/cli.py", line 829, in addsig_pkcs11
generic_sign(
File "/usr/local/lib64/python3.8/site-packages/pyhanko/cli.py", line 689, in generic_sign
result = signers.PdfSigner(
File "/usr/local/lib64/python3.8/site-packages/pyhanko/sign/signers.py", line 2277, in sign_pdf
test_signature_cms = signer.sign(
File "/usr/local/lib64/python3.8/site-packages/pyhanko/sign/signers.py", line 710, in sign
signed_attrs = self.signed_attrs(
File "/usr/local/lib64/python3.8/site-packages/pyhanko/sign/signers.py", line 533, in signed_attrs
general.as_signing_certificate(self.signing_cert)
File "/usr/local/lib64/python3.8/site-packages/pyhanko/sign/pkcs11.py", line 159, in signing_cert
self._load_objects()
File "/usr/local/lib64/python3.8/site-packages/pyhanko/sign/pkcs11.py", line 268, in _load_objects
kh, = list(q)
ValueError: not enough values to unpack (expected 1, got 0)
Error: Generic processing error.

Then, I tried to do it using a python code which it is as follows:

`import os
 from io import BytesIO

 import pytest
 import logging
 from freezegun import freeze_time

 from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
 from pyhanko.pdf_utils.reader import PdfFileReader
from pyhanko.sign import signers, pkcs11

#from pyhanko_tests.test_signing import val_trusted, SIMPLE_ECC_V_CONTEXT

def read_all(fname):
     with open(fname, 'rb') as f:
         return f.read()



MINIMAL_PATH = '../lorem-f.pdf'

MINIMAL = read_all(MINIMAL_PATH)
logger = logging.getLogger(__name__)

SKIP_PKCS11 = False



def _simple_sess():
   lib = "/usr/lib64/libpkcs11-fnmtdnie.so"
   session=pkcs11.open_pkcs11_session(
   lib, user_pin='p4rp4rp4arpxp2', token_label='DNI electrónico (PIN1)'
    )

   return session


default_other_certs = ('CertCAIntermediaDGP',)



def test_simple_sign(bulk_fetch, pss):

   w = IncrementalPdfFileWriter(BytesIO(MINIMAL))
   meta = signers.PdfSignatureMetadata(field_name='Sigg2')
   with _simple_sess() as sess:
        signer = pkcs11.PKCS11Signer(
              sess, 'CertFirmaDigital', other_certs_to_pull=default_other_certs,
              bulk_fetch=bulk_fetch, prefer_pss=pss
    )
    print(signer)
    
    out = signers.sign_pdf(w, meta, signer,None,None,False,None,False,None)

r = PdfFileReader(out)
emb = r.embedded_signatures[0]
assert emb.field_name == 'Sigg1'
val_trusted(emb)




test_simple_sign(True,False)`

And get the same error in "out=signers.sign_pdf (....)" whic is "Exception has occurred: ValueError
not enough values to unpack (expected 1, got 0)"

But using:

`for cert in session.get_objects({ Attribute.LABEL: "CertFirmaDigital",
 Attribute.CLASS: ObjectClass.CERTIFICATE,}):   
    der_bytes = cert[Attribute.VALUE]

 # Load a certificate object from the DER-encoded value
  cert = x509.Certificate.load(der_bytes)
  print(cert)`

I am getting the signature certificate.

Any help will be appreciated
Thanks in advance

Exception when signing a PDF with filled forms

Hey Matthias,

I have been playing arround the subject of our last discussion: signing filled forms, but hit a roadblock. Here it is:

Describe the bug
I get pyhanko.pdf_utils.misc.PdfReadError when signing a pdf with any filled form I could find. Perhaps the forms are not A-grade and are the root cause of the issue, or the programs I am using to fill them (okular and evince). I can sign any pdf with forms just fine if and only if they are empty.

To Reproduce

  1. Download example.zip
  2. Fill the form.pdf and save the resulting pdf under the same name
  3. Run python3 sign.py to sign the filled form and get an error like pyhanko.pdf_utils.misc.PdfReadError: Generation 0 of object 3 was never freed, but reused later.

Expected behavior
No errors and a signed pdf.

Environment (please complete the following information):

  • OS: ubuntu
  • Version: 21.04

Allow PKCS#11 token settings to be read from the configuration file

Hi, Matthias. I am trying to sign a PDF but encountered the following:
Command:
pyhanko sign addsig --field Sig1 beid --lib /usr/lib/libaetpkss.so ii.pdf o.pdf

Error:
(several lines eliminated...)

raise PKCS11Error(
pkcs11.exceptions.PKCS11Error: Could not find (unique) cert with label 'Root'.
Error: Generic processing error.

Perhaps the issue has to do with beid, but I don't know what to put in place.

Also, It would be very good if you could point me towards a sample code the allows me to sign a PDF using the API instead of using the CLI.

Thank you.

Fernando Cabral

`pdf_date()` function outputs wrong dates when the input has a negative UTC offset

This bug was originally reported by @fredericoschardong in #31 (thanks!).


The pdf_date function has been broken in a very particular way since it was first defined (see 543aac7). When passed a datetime with a negative UTC offset, the seconds field of the resulting timedelta is positive, and the days field is set to -1. Our pdf_date function simply proceeds with the value in the seconds field, resulting in a PDF date string that's off by one day.

Error: Failed to read PDF file.

1 uploads/61cd28fb986c7817124531770sample.pdf uploads/1_out_61cd28fb986c7817124531770sample.pdf uploads/1_signed_61cd28fb986c7817124531770sample.pdf
Executing Command : pyhanko sign addfields --field 1/1,1,100,50/signature1 uploads/61cd28fb986c7817124531770sample.pdf uploads/1_out_61cd28fb986c7817124531770sample.pdf
(node:7556) UnhandledPromiseRejectionWarning: Error: Command failed: pyhanko sign addfields --field 1/1,1,100,50/signature1 uploads/61cd28fb986c7817124531770sample.pdf uploads/1_out_61cd28fb986c7817124531770sample.pdf
2021-12-30 10:16:56,111 - pyhanko.cli - ERROR - Failed to read PDF file.
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/pyhanko/cli.py", line 80, in pyhanko_exception_manager
yield
File "/usr/local/lib/python3.9/site-packages/pyhanko/cli.py", line 1205, in add_sig_field
writer = IncrementalPdfFileWriter(infile)
File "/usr/local/lib/python3.9/site-packages/pyhanko/pdf_utils/incremental_writer.py", line 41, in init
prev = PdfFileReader(input_stream)
File "/usr/local/lib/python3.9/site-packages/pyhanko/pdf_utils/reader.py", line 617, in init
self.read()
File "/usr/local/lib/python3.9/site-packages/pyhanko/pdf_utils/reader.py", line 972, in read
self._read_xrefs()
File "/usr/local/lib/python3.9/site-packages/pyhanko/pdf_utils/reader.py", line 940, in _read_xrefs
raise PdfReadError(
pyhanko.pdf_utils.misc.PdfReadError: Xref table contains orphaned higher generation objects: 78 39 obj,80 37 obj,82 35 obj,84 33 obj,86 31 obj,101 1 obj

Remote Signature Device Support?

Hi! Thanks for this project, a good PDF signing library for Python was missing!

I have a mechanism for remote signature creation, i.e., I have an interface where I can provide the hash of a PDF document (already prepared with an empty signature placeholder) from the interface I get back a CMS object representing the signature for this document and the certificate of the signer; potentially I get some revocation information as well.

Compared to the BeID example that you already provide, there are some differences for this remote signature interace. Most importantly, I cannot know the signer's certificate beforehand, as this certificate is short-lived and is created on-demand.

I would be happy to provide code for remote signature devices for your library. It seems that implementing a Signer class is the way to go, but from what I saw so far it seems that the library assumes that the certificate is known beforehand. It would be great if you could provide me some pointers on the following topics:

  • What are the interfaces I would need to implement to just grab the hash of a prepared document?
  • How would I provide the CMS object and revocation information to your library?

Validation errors after upgrading pyhanko-certvalidator from 0.12.1 to 0.15.1

Describe the bug
During validation of a pdf file with three signatures, have met with the following warning and the following error:

2021-05-20 09:47:22,762 - pyhanko.sign.diff_analysis - WARNING - Error in diff operation between revision 1 and 2
Traceback (most recent call last):
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\diff_analysis.py", line 2130, in review_file
    diff_result = self.apply(
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\diff_analysis.py", line 2030, in apply
    for level, fu in form_changes:
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\diff_analysis.py", line 1168, in apply
    _compare_dicts(old_acroform, new_acroform, self.ignored_acroform_keys)
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\diff_analysis.py", line 1705, in _compare_dicts
    raise SuspiciousModification(
pyhanko.sign.diff_analysis.SuspiciousModification: Dict keys differ: {'/DA', '/SigFlags'} vs. {'/SigFlags'}.
2021-05-20 09:47:23,482 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\cli.py", line 69, in pyhanko_exception_manager
    yield
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\cli.py", line 437, in validate_signatures
    status_str = _signature_status(
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\cli.py", line 327, in _signature_status
    status = validation.validate_pdf_signature(
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\validation.py", line 1263, in validate_pdf_signature
    status_kwargs = _validate_cms_signature(
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\validation.py", line 178, in _validate_cms_signature
    trusted, revoked, path = status_cls.validate_cert_usage(
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\sign\general.py", line 359, in validate_cert_usage
    path = validator.validate_usage(key_usage=set())
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\__init__.py", line 211, in validate_usage
    self._validate_path()
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\__init__.py", line 139, in _validate_path
    validate_path(self._context, candidate_path, self._params)
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\validate.py", line 70, in validate_path
    return _validate_path(validation_context, path, parameters=parameters)
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\validate.py", line 592, in _validate_path
    _check_revocation(
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\validate.py", line 786, in _check_revocation
    verify_crl(
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\validate.py", line 1500, in verify_crl
    certificate_lists = validation_context.retrieve_crls(cert)
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\context.py", line 465, in retrieve_crls
    certs = crl_client.fetch_certs(
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\pyhanko_certvalidator\crl_client.py", line 125, in fetch_certs
    content_type = response.headers['Content-Type'].strip()
  File "c:\Users\guilhermec\source\repos\pyHanko\env\lib\site-packages\requests\structures.py", line 54, in __getitem__
    return self._store[key.lower()][1]
KeyError: 'content-type'
Error: Generic processing error.

To Reproduce
python -mpyhanko sign validate --pretty-print testdata/teste3.pdf
The used file is attached

Expected behavior
The two first signatures should be valide (if Brazilian CA roots are used), the last one invalid since it used a self-signed certificate.

Environment (please complete the following information):

  • OS: Windows 10, python 3.9.5
  • Version commit fd1af25

Screenshots
The same validation using adobe reader
image

Timestamp, Adobe Reader & "date/time are from the clock on the signer’s computer"

Hi!

First, congrats for the project! It's fantastic!

I have a quirk about the time stamp and, well, I don't know if it's a feature of the project or some wrong implementation I did.

I'm getting a valid timestamp from a server and embedding it in the code. However, when I sign the PDF, Adobe Reader/Acrobat reports that “signature date/time are from the clock on the signer’s computer”.

Do the output PDF (digital signature + timestamped) have "correct" timestamp validation when opened in Adobe (“The signature includes an embedded timestamp”), or is it anyway - i.e., will this message always appear?

Font Postcript name in TextBoxStyle - cannot make works

Hi everyone. After updating pyhanko from 0.6.0 to 0.8.0, I am not able to choose the font for a visible signature. Only the "NotoSans-Regular" works. I have downloaded a lot of ttf unicode fonts , but always I get

Could not deduce PostScript name for font; only unicode-compatible encodings in the name table are supported. This is may code line:

tbst=TextBoxStyle(opentype.GlyphAccumulatorFactory('linux-biolinum-capitals-italic.ttf'))

Also I have tried with:

letra=SimpleFontEngine(writer.BasePdfFileWriter.get_subset_collection(self=root, base_postscript_name='ArialMT-Bold'), name='ArialMT-Bold',avg_width=1)

with the result:

'_tkinter.tkapp' object has no attribute '_font_resources'

Don't know what to do.
Any helps will be appreciated

Thanks in advance

Exception when validating a PDF

Describe the bug

Trying to validate a PDF with pyhanko sign validate and I got a Traceback with KeyError.

To Reproduce

Execute

pyhanko sign validate --pretty-print  signed-lorem-ipsum.pdf

I got:

022-02-03 14:54:47,419 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 164, in queue_fetch_task
    wait_event: asyncio.Event = running_jobs[tag]
KeyError: 'https://www.sk.ee/upload/files/TEST_of_EE_Certification_Centre_Root_CA.der.crt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "$VENV/lib/python3.8/site-packages/pyhanko/cli.py", line 78, in pyhanko_exception_manager
    yield
  File "$VENV/lib/python3.8/site-packages/pyhanko/cli.py", line 529, in validate_signatures
    (status_str, signature_ok) = _signature_status_str(
  File "$VENV/lib/python3.8/site-packages/pyhanko/cli.py", line 387, in _signature_status_str
    status = status_callback()
  File "$VENV/lib/python3.8/site-packages/pyhanko/cli.py", line 530, in <lambda>
    status_callback=lambda: _signature_status(
  File "$VENV/lib/python3.8/site-packages/pyhanko/cli.py", line 349, in _signature_status
    status = pyhanko.sign.validation.validate_pdf_signature(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/__init__.py", line 221, in validate_pdf_signature
    return asyncio.run(coro)
  File "/Users/tlilja/.pyenv/versions/3.8.10/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/Users/tlilja/.pyenv/versions/3.8.10/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/pdf_embedded.py", line 845, in async_validate_pdf_signature
    ts_status_kwargs = await collect_timing_info(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/generic_cms.py", line 432, in collect_timing_info
    tst_validity_kwargs = await validate_tst_signed_data(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/generic_cms.py", line 492, in validate_tst_signed_data
    return await cms_basic_validation(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/generic_cms.py", line 270, in cms_basic_validation
    trusted, revoked, path = await status_cls.validate_cert_usage(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/status.py", line 154, in validate_cert_usage
    path = await validator.async_validate_usage(key_usage=set())
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/__init__.py", line 263, in async_validate_usage
    await self._validate_path()
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/__init__.py", line 107, in _validate_path
    paths = await self._context.certificate_registry.async_build_paths(
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/registry.py", line 323, in async_build_paths
    await self._walk_issuers(path, paths, failed_paths)
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/registry.py", line 375, in _walk_issuers
    async for issuer in self.fetcher.fetch_cert_issuers(path.first):
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 268, in complete_certificate_fetch_jobs
    certs_fetched = await fetch_job
  File "$PYENV/versions/3.8.10/lib/python3.8/asyncio/tasks.py", line 619, in _wait_for_one
    return f.result()  # May raise f.exception().
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 57, in fetch_certs
    return await self._perform_fetch(url, task)
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/util.py", line 37, in _perform_fetch
    return await queue_fetch_task(
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 195, in queue_fetch_task
    return _return_or_raise(result)
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 200, in _return_or_raise
    raise result
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 182, in queue_fetch_task
    result = await async_fun()
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 49, in task
    results = await self._grab_certs(
  File "$VENV/lib/python3.8/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 103, in _grab_certs
    content_type = response.headers['Content-Type'].strip()
  File "$VENV/lib/python3.8/site-packages/requests/structures.py", line 54, in __getitem__
    return self._store[key.lower()][1]
KeyError: 'content-type'
Error: Generic processing error.

Expected behavior

No traceback. Perhaps error message or successful validation?

Environment (please complete the following information):

pyHanko==0.12.0
pyhanko-certvalidator==0.19.2

Additional context

Looks like https://www.sk.ee/upload/files/TEST_of_EE_Certification_Centre_Root_CA.der.crt is serving the file without Content-Type header and hence the error.

pdf encrypted by owner password and keep user password empty if not set.

currently the encrypt function is working good, with only one problem.
I'm using it to encrypt and sign PDF certificates and then release to public, alrough the signed documents are protected for altering, however, what I need is also that the PDF are protected against content copy, I managed to sub-class the PdfFileWriter and set the perms=2500 and which works as expected. user can open the pdf via the user_password and view the pdf.
The only problem is that I also need to left user_password empty so that public users can just open the certificate and view the content althrough they are not allowed to copy the conent to DOC etc.
my code as following:

def generate_certificate(self):
    from pyhanko.sign import signers
    from pyhanko.pdf_utils.reader import PdfFileReader
    from mysite.lib.pdf import  copy_into_new_writer
    password = current_app.config['PDF_PASSWORD']
    path = self.file_uploaded_path()
    certificate_url = url_for(
        'web.validate_certificate', id=self.id, utn=self.utn, _external=True)
    if not self.draft:
        raise NotFound(
            'certicate draft for certificat line {} not found.'.format(self.id))
    buffer = io.BytesIO()
    filename = os.path.join(path, self.draft)
    with open(filename, 'rb') as fp:
        b_in = io.BytesIO(fp.read())
    input = PdfFileReader(b_in)
    w = copy_into_new_writer(input)
    w.encrypt(password, '123456')
    out_filename = os.path.join(path, self.filename)
    cms_signer = signers.SimpleSigner.load('test.key', 'test.pem', key_passphrase=b'wswa2011')
    out = signers.PdfSigner(signers.PdfSignatureMetadata(field_name='Signature1'),
                            signer=cms_signer,).sign_pdf(w)
    with open(out_filename, 'wb+') as fp:
        fp.write(out.getvalue())

Support filling text fields & rendering corresponding annots accordingly

Hi Matthias,

I would like to kindly ask for your guidance once again. I have a similar objective as reported in #6. Let me explain.

I have a PDF whose entire content is signed with pyHanko. Now, I would like to: (i) add a few strings to the signed pdf by x/y coordinates; and (ii) sign only whatever was added after the first signature.

Regarding (i), after looking at the documentation and source code, there doesn't seem to be a readily available class/method for writing strings to the pdf. If that is indeed the case, what would be the straightforward way of doing so? What comes to mind is to mimic what is done in this method.

Regarding (ii) I am not sure where to start :-)

Diff analysis can't deal with references to undefined/freed objects

Describe the bug

The difference analysis tool that performs comparisons between revisions of the same PDF file doesn't correctly process references to objects that are undefined or freed.
The standard mandates that such references be treated as nulls. Of course, nothing prevents us from considering such references as suspicious anyway (there's a sound security argument to be made for that), but at least we need to treat them gracefully.

To Reproduce

Take a PDF document containing a reference to a freed object or an undefined one. Sign it twice and attempt to validate the first signature. An ugly stack trace ensues.

Expected behavior

SuspiciousModification exception, or assume null.

Additional context

Reported in #54.

Signing documents with an Estonian ID

Thanks for such a useful little tool! I'm trying to utilize it to sign a PDF using my Estonian ID card. So far by trial and error, I've managed to get to this command:

pyhanko sign addsig pkcs11 \
  --lib /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so \
  --token-label 'PUSHKOV,ALEKSANDR,3970... (PIN2)' \
  --cert-label 'Allkirjastamine' \
  test.pdf signed.pdf

But it fails with the pkcs11.exceptions.MechanismInvalid error.

Full output
PKCS#11 user PIN: 
2021-09-27 18:33:09,048 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/cli.py", line 75, in pyhanko_exception_manager
    yield
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/cli.py", line 981, in _sign_pkcs11
    generic_sign_pdf(
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/cli.py", line 795, in generic_sign_pdf
    result = signers.PdfSigner(
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_signer.py", line 990, in sign_pdf
    post_signing_doc = tbs_document.perform_signature(
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_signer.py", line 1687, in perform_signature
    signature_cms = self.signer.sign(
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_cms.py", line 465, in sign
    return self.sign_prescribed_attributes(
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_cms.py", line 538, in sign_prescribed_attributes
    signature = self.sign_raw(
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pyhanko/sign/pkcs11.py", line 266, in sign_raw
    signature = kh.sign(data, **kwargs)
  File "/home/ale/.local/pipx/venvs/pyHanko/lib/python3.8/site-packages/pkcs11/types.py", line 939, in sign
    return self._sign(data, **kwargs)
  File "pkcs11/_pkcs11.pyx", line 1072, in pkcs11._pkcs11.SignMixin._sign
  File "pkcs11/_pkcs11.pyx", line 1074, in pkcs11._pkcs11.SignMixin._sign
  File "pkcs11/_errors.pyx", line 88, in pkcs11._pkcs11.assertRV
pkcs11.exceptions.MechanismInvalid
Error: Generic processing error.

I've added a couple quick prints to pyhanko.sign.pkcs11.PKCS11Signer.sing_raw to verify that the mechanism picked is indeed correct and it seems plausible to me:

signature_algo: ecdsa
digest_algorithm: sha256

Here's some info about the certificate and the card itself:

$ pkcs11-tool --slot 1 -OM
Supported mechanisms:
  SHA-1, digest
  SHA224, digest
  SHA256, digest
  SHA384, digest
  SHA512, digest
  MD5, digest
  RIPEMD160, digest
  GOSTR3411, digest
  ECDSA, keySize={384,384}, hw, sign, other flags=0x1800000
  ECDH1-COFACTOR-DERIVE, keySize={384,384}, hw, derive, other flags=0x1800000
  ECDH1-DERIVE, keySize={384,384}, hw, derive, other flags=0x1800000
Certificate Object; type = X.509 cert
  label:      Allkirjastamine
  subject:    DN: C=EE, O=ESTEID, OU=digital signature, CN=PUSHKOV,ALEKSANDR,397xxxxxxxx, SN=PUSHKOV, GN=ALEKSANDR/serialNumber=397xxxxxxxx
  ID:         02
Public Key Object; EC  EC_POINT 384 bits
  EC_POINT:   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  EC_PARAMS:  06052b81040022
  label:      Allkirjastamine
  ID:         02
  Usage:      encrypt, verify
  Access:     local

What are my next steps to solve this mystery? :-)

Automating CLI tests

Note: this grew out of a conversation with @fornwall on PR #33 .

As I mentioned over there, the CLI code used to be much more of a thin wrapper around pyHanko's internals. However, as time went on, it gradually evolved into something more complex. I'd like to refactor the CLI wrapper code into something more modular, but that's not the thing that's at issue here.

The library code has a lot of tests, and almost all of these run in Github Actions as well (the PKCS#11 tests being a notable exception). The CLI code isn't tested anywhere near as rigorously. There's certainly a lot of room for improvement there. I've put some of my own thoughts below.


I think we can approach this problem from two angles:

  • Write some standard pytest tests that call click's entry points
  • Use a CLI testing tool (like bats) to invoke pyHanko from an actual shell

I'm not sure which of these would be better (although nothing stops us from doing both, of course).
Here's what I think:

  • The first testing strategy has the advantage of being easy to plug into our current test suite: we could use existing validation tools and existing Certomancer mocks for code that talks to trust services. However, there is some I/O in the CLI code that doesn't do everything through click (mainly password prompts), that will require some care.
  • I've never used bats-like testing tools, but you could argue that those would provide a more complete/representative integration test suite. I certainly wouldn't object to that. The main difficulties here will be in deciding what kind of assertions to write (without relying too much on pyHanko internals), and in setting up our trust services mocks properly.

Note: Certomancer can still handle the second scenario, but it will require some care to set up correctly (and we might have to tweak the existing test setup a little in order to make it work using the same configuration for both CLI tests and library tests).


Anyway, let's discuss here. I'm happy to consider a PR to address CLI tests, but I'd like to get a sense of direction here first, so we don't waste time and effort arguing over test strategies after the code has been written :).

Obviously, I can also help with the Certomancer setup for testing commands that require OCSP/CRL/TSA access. If getting this right requires tweaking things in Certomancer: we can discuss that as well.

Coredump when importing pyhanko in pdfarranger

I'm trying to include signing features in pdfarranger using pyhanko, but on my first import of pyhanko modules the application coredumps. This is the very specific line which causes the coredump: https://github.com/plenaerts/pdfarranger/blob/a96db16096ca80e2af01be4f151c5e41fc58b1a6/pdfarranger/signer.py#L104

I tested using the pyhanko API in this script but once I try reusing this code in the gtk application I don't get to import pyhanko modules.

I don't have a clue where to start looking what causes this. Anyone else?

'SigFieldSpec' Object is not iterable

According to documentation, I am trying to add a signature field to a PDF document, so:

This is my code:

  `from  pyhanko.sign.fields import append_signature_fields,SigFieldSpec
   from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
   with open('output-signed.pdf', 'rb+') as doc:
                w = IncrementalPdfFileWriter(doc)      
                append_signature_fields(w, SigFieldSpec(sig_field_name='Sig'))
                w.write_in_place()`

I had to change"append_signature_field" for "append_signature_fields", but no matter the parameters I add to SigFieldSpec, that I have always the same result which is 'SigFieldSpec' object is not iterable.

But my CLI version works perfecly

Any help will be grateful
Thanks in advance

Support hybrid reference documents

Is your feature request related to a problem? Please describe.

PyHanko supports PDF documents with traditional cross-reference tables and documents with cross-reference streams. Hybrid reference documents aren't currently supported, though. Those make use of a standard cross-reference table with the XrefStm directive to get support for PDF 1.5 features in a document that's still (mostly) understandable to a PDF 1.4 reader. PDF readers without support for PDF 1.5 have all but disappeared, but some PDF producer tools still generate such hybrid-reference files to this day (looking at you, MS Office). Those documents are pretty rare in the grand scheme of things, but still common enough that we should support them properly.

Describe the solution you'd like

Four items:

  • Support reading hybrid-reference docs.
  • Support making incremental updates to hybrid-reference docs.
  • Ensure creation & validation of signatures in hybrid-reference documents is opt-in (due to the inherent parser differential).
  • Have the difference analysis tooling account for the quirks of hybrid-reference docs as well.

It's all very straightforward in principle, but there are quite a few sharp edges, esp. with regards to the last point.

Sign PDF with not encrypted key in pemder mode

Is your feature request related to a problem? Please describe.
I have an not encrypted key RSA key and certificate and like to use that in pemder mode.
It asks for an 'Key passphrase' and returns 'TypeError: Password was given but private key is not encrypted.' if I enter an empty one.

Describe the solution you'd like
Add an parameter like "--unencrypted" to skip requesting the 'Key passphrase'

LTV non-repudiation error

Hello Matthias,

First of all great work you have done with pyHanko.

Describe the bug
We are planning on using pyHanko on a large scale for signed pdf docs for the Greek public sector. For that we need
the signed documents to be LTV enabled. I have tried to make an initial implementation but when I use the param embed_validation_info I get an pyhanko.sign.general.SigningError: ("The signer's certificate could not be validated", InvalidCertificateError('The X.509 certificate provided is not valid for the purpose of non repudiation')) error.

To Reproduce
The code I have written so far looks like this

    cms_signer = signers.SimpleSigner.load_pkcs12(
        certificate_filename, passphrase=password.encode('utf-8'))
    
    w = IncrementalPdfFileWriter(pdf_buffer)
    tst_client = timestamps.HTTPTimeStamper('https://timestamp.aped.gov.gr/qtss')

    sv = fields.SigSeedValueSpec(
        reasons=[],
        digest_methods=[],
        flags=3,
    )

    sp = fields.SigFieldSpec('Signature', seed_value_dict=sv, box=(15, 705, 175, 798))

    image = PdfImage(image=settings.STAMP_IMAGE)

    style = TextStampStyle(background=image, border_width=0)
    
    vc = ValidationContext(trust_roots=[cms_signer.signing_cert])
    
    out = signers.PdfSigner(signature_meta=signers.PdfSignatureMetadata(
                                            field_name='Signature',
                                            reason='My reason',
                                            location='My location',
                                            use_pades_lta=True,
                                            subfilter=fields.SigSeedSubFilter.PADES,
                                            embed_validation_info=True,
                                            validation_context=vc
                                            ),
                            signer=cms_signer,
                            timestamper=tst_client,
                            stamp_style=style,
                            new_field_spec=sp
                            ).sign_pdf(w)

Where the certificate_filename is a p12 signing certificate and pdf_buffer is the document I want to sign in BytesIO

Expected behavior
In the end I expect a signed document that when opened with Adobe Acrobat Reader it is listed as "LTV enabled"

Screenshots
Screenshot 2021-03-13 at 21 50 35

Environment (please complete the following information):

  • Docker with python:3.7 image
  • MacOS 11.2.2

Additional context
The same issue exists in both 0.4.0 as well as 0.5.0-dev1

I have contaced HARICA which is the Hellenic Academic & Research Institutions Certification Authority and they told me that non-repudiaton has nothing to do with LTV and it shouldn't be needed to LTV enable a document.

SignatureValidationError: LTV signatures require a trusted timestamp

Hi Matthias! A great Python library you've made there so far!

Describe the bug
I try to use pyHanko to validate PDFs that have LTV enabled signatures. What I do now is execute pyHanko with the following CLI command:

python3 -m pyhanko --config "C:/Users/Leon/Desktop/Verification/pyhanko.yml" sign validate "C:/Users/Leon/Desktop/Verification/signed_pdf.pdf" --ltv-profile adobe --validation-context standart1
at the --ltv-profile option, I tried all 3 accepted values adobe, pades and pades-lta.

When I use adobe, pyHanko returns pyhanko.sign.general.SignatureValidationError: LTV signatures require a trusted timestamp.

When I use pades, pyHanko returns pyhanko.cli - ERROR - An error occurred while parsing the revocation information for this signature: No DDS found - same is returned for pades-lta.

To Reproduce
python3 -m pyhanko --config "C:/Users/Leon/Desktop/Verification/pyhanko.yml" sign validate "C:/Users/Leon/Desktop/Verification/signed_pdf.pdf" --ltv-profile adobe --validation-context standart1
at the --ltv-profile option I tried all 3 accepted values adobe, pades and pades-lta

The configuration used looks like this:

pyHanko_sample_config

Expected behavior
I expect to return the same output like when not using --ltv-profile (see below at Additional Context).

Screenshots

valid_and_ltv_enabled
As you can see above in the screenshot, it seems like LTV is enabled.

Environment (please complete the following information):

  • OS: Windows 10 Enterprise 21H1
  • Python Version: 3.9.7
  • pyHanko Version: 0.9.0

Additional context

The CLI command without the --ltv-profile works like a charm and returns INTACT:TRUSTED:UNTOUCHED.


Thanks and best regards,
Leon Dierkes

Unable to build a validation path for the certificate

Hello Matthias,
i got a problem with this command
pyhanko sign addsig --field Sig1 --timestamp-url http://tsa.example.com
--with-validation-info --use-pades pemder
--key key.pem --cert cert.pem input.pdf output.pdf
the result
2021-07-29 13:51:42,948 - pyhanko.cli - ERROR - Error raised while producing signed file.
Traceback (most recent call last):
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_signer.py", line 959, in _perform_presign_signer_validation
signer_cert_validation_path = validator.validate_usage(key_usage)
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko_certvalidator/init.py", line 212, in validate_usage
self._validate_path()
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko_certvalidator/init.py", line 127, in _validate_path
paths = self._context.certificate_registry.build_paths(self._certificate)
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko_certvalidator/registry.py", line 314, in build_paths
raise PathBuildingError(pretty_message(
pyhanko_certvalidator.errors.PathBuildingError: Unable to build a validation path for the certificate "Common Name: Danny Jawa Timur; Country: ID" - no issuer matching "Common Name: iXXX CA G1, Organizational Unit: iXXXX, Organization: XXX, Country: ID" was found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/cli.py", line 75, in pyhanko_exception_manager
yield
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/cli.py", line 781, in addsig_simple_signer
generic_sign_pdf(
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/cli.py", line 791, in generic_sign_pdf
result = signers.PdfSigner(
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_signer.py", line 764, in sign_pdf
validation_info = signing_session.perform_presign_validation(pdf_out)
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_signer.py", line 904, in perform_presign_validation
signer_path = self._perform_presign_signer_validation(
File "/home/dany/.local/lib/python3.8/site-packages/pyhanko/sign/signers/pdf_signer.py", line 961, in _perform_presign_signer_validation
raise SigningError(
pyhanko.sign.general.SigningError: ("The signer's certificate could not be validated", PathBuildingError('Unable to build a validation path for the certificate "Common Name: XXXX; Organization: XXX; Country: ID" - no issuer matching "Common Name: iXXX CA G1, Organizational Unit: iXXXX, Organization: XXX, Country: ID" was found'))
Error: Error raised while producing signed file.
please help me solve this problem

verify https://autenti.com/ signed pdf by pyhanko

pyHanko-0.9.0 on linux Python 3.7.3

pdf signed on https://autenti.com/
after

./.local/bin/pyhanko sign validate --pretty-print PDF_sign_test.pdf

I got:

2021-11-13 20:09:13,402 - pyhanko.sign.diff_analysis - WARNING - Error in diff operation between revision 1 and 5
Traceback (most recent call last):
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 2240, in review_file
    field_mdp_spec=field_mdp_spec, doc_mdp=doc_mdp
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 2131, in apply
    for level, fu in form_changes:
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 1304, in apply
    yield from rule.apply(context)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 981, in apply
    yield from self.check_form_field(fq_name, spec, context)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 1046, in check_form_field
    valid_when_locked = self.compare_fields(spec)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 971, in compare_fields
    old_field, new_field, self.value_update_keys
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/diff_analysis.py", line 1806, in _compare_dicts
    f"Dict keys differ: {new_dict_keys} vs. "
pyhanko.sign.diff_analysis.SuspiciousModification: Dict keys differ: {'/Lock', '/P', '/Rect', '/FT', '/Subtype', '/T'} vs. {'/P', '/Rect', '/FT', '/Subtype', '/T'}.
2021-11-13 20:09:13,412 - pyhanko.sign.general - WARNING - Unable to build a validation path for the certificate "Organization Identifier: VATPL-5170359458, Common Name: Certum QTST 2017, Organization: Asseco Data Systems S.A., Country: PL" - no issuer matching "Organization Identifier: VATPL-5250008198, Common Name: Narodowe Centrum Certyfikacji, Organization: Narodowy Bank Polski, Country: PL" was found
2021-11-13 20:09:13,412 - pyhanko.sign.general - WARNING - Chain of trust validation for Organization Identifier: VATPL-5170359458, Common Name: Certum QTST 2017, Organization: Asseco Data Systems S.A., Country: PL failed.
2021-11-13 20:09:13,436 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 139, in queue_fetch_task
    wait_event: asyncio.Event = running_jobs[tag]
KeyError: 'http://elektronicznypodpis.pl/certyfikaty/ozk62.der'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/cli.py", line 80, in pyhanko_exception_manager
    yield
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/cli.py", line 518, in validate_signatures
    pretty_print=pretty_print, executive_summary=executive_summary
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/cli.py", line 386, in _signature_status_str
    status = status_callback()
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/cli.py", line 516, in <lambda>
    embedded_sig=embedded_sig
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/cli.py", line 352, in _signature_status
    signer_validation_context=vc
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/validation.py", line 1569, in validate_pdf_signature
    return asyncio.run(coro)
  File "/usr/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/validation.py", line 1639, in async_validate_pdf_signature
    status_kwargs=status_kwargs, key_usage_settings=key_usage_settings
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/validation.py", line 266, in _validate_cms_signature
    validator, key_usage_settings=key_usage_settings
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko/sign/general.py", line 373, in validate_cert_usage
    path = await validator.async_validate_usage(key_usage=set())
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/__init__.py", line 283, in async_validate_usage
    await self._validate_path()
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/__init__.py", line 128, in _validate_path
    self._certificate
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/registry.py", line 426, in async_build_paths
    await self._walk_issuers(path, paths, failed_paths)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/registry.py", line 478, in _walk_issuers
    async for issuer in self.fetcher.fetch_cert_issuers(path.first):
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 70, in fetch_cert_issuers
    url, url_origin_type='certificate'
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 56, in fetch_certs
    return await self._perform_fetch(url, task)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/util.py", line 38, in _perform_fetch
    self.__results, self.__result_events, tag, fetch_fun
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 170, in queue_fetch_task
    return _return_or_raise(result)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 175, in _return_or_raise
    raise result
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 157, in queue_fetch_task
    result = await async_fun()
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 55, in task
    return list(results)
  File "/home/eod/.local/lib/python3.7/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 46, in unpack_cert_content
    "Expected PEM data when extracting certs from "
ValueError: Expected PEM data when extracting certs from application/x-x509-ca-cert payload. Source URL: http://elektronicznypodpis.pl/certyfikaty/ozk62.der.
Error: Generic processing error.

what I did wrong ?

PDF_sign_test.pdf
?

Error when trying to sign using a p12 certificate file

I have upgraded my system and python has upgraded from 3.8 to 3.9. On version 3.8 everything worked fine, but now I have got this error which I do not know how to solve. Error occurs when I get a p12 file certificate to sign, when is verifying the certificate. This is the error:
File "/root/Descargas/programacion/firma_digital/pades_sign/firma_final.py", line 307, in certificadodig out = signers.PdfSigner(signature_meta=signers.PdfSignatureMetadata( File "/usr/local/lib/python3.9/site-packages/pyhanko/sign/signers.py", line 2198, in sign_pdf signer_cert_validation_path = validator.validate_usage( File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/__init__.py", line 211, in validate_usage self._validate_path() File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/__init__.py", line 139, in _validate_path validate_path(self._context, candidate_path, self._params) File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/validate.py", line 70, in validate_path return _validate_path(validation_context, path, parameters=parameters) File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/validate.py", line 661, in _validate_path qualified_policies = _finish_policy_processing( File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/validate.py", line 741, in _finish_policy_processing qualified_policies = frozenset(_enum_policies()) File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/validate.py", line 732, in _enum_policies user_domain_policy_id=next( File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/validate.py", line 735, in <genexpr> if ancestor.parent.valid_policy == 'any_policy' AttributeError: 'PolicyTreeRoot' object has no attribute 'valid_policy'

My pyhanko version is 0.6.1 and the pyhanko-certvalidator is 0.15.1 (I have als tested 0.15.2 with same result)

The code is :

 ` def certificadodigper(x1,y1,x2,y2,fname):
    try:  
        root.filename =  filedialog.askopenfilename(initialdir = ".",title = "Seleccione archivo",filetypes = (("p12 files","*.p12"),("all files","*.*")))
        finame=root.filename
        w = IncrementalPdfFileWriter(BytesIO(MINIMAL))
        pin=simpledialog.askstring(title = 'Introduzca PIN', prompt='PIN secreto', show ='*')
        FROM_CA_PKCS12 = signers.SimpleSigner.load_pkcs12(
        finame, passphrase=bytes(pin,'utf-8'))

        p12 = crypto.load_pkcs12(open(finame, 'rb').read(), bytes(pin,'utf-8'))


        acert=p12.get_certificate()     # (signed) certificate object
        bkey=p12.get_privatekey()      # private key.
        cinter=p12.get_ca_certificates() # ca chain.   



        certs =crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, acert)
        certt2=crypto.load_certificate(FILETYPE_PEM,certs)
        subject=certt2.get_subject()
        print(subject)

        nombre = dict(subject.get_components())[b'CN'].decode()
        cif = dict(subject.get_components())[b'serialNumber'].decode()
        #empresa=dict(subject.get_components())[b'O'].decode()
        privkey=crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, bkey)
        datos_firma=f'Firma digital por:\n\n{nombre}.\n\nDNI/CIF:{cif}\n'
        sv = fields.SigSeedValueSpec(
                reasons=[],            
                flags=3,
                )

        
        letra=SimpleFontEngine('Arial-BoldMT',0.4)  
        sp = fields.SigFieldSpec('Sigg1', seed_value_dict=sv, on_page=pagina_firma-1, box=(x1, y1, x2, y2),)
        tbst=TextBoxStyle( letra,)
            #image = PdfImage(image=settings.STAMP_IMAGE)
        vc = ValidationContext(trust_roots=[FROM_CA_PKCS12.signing_cert])    
        if (firma.ci==False):
            style=TextStampStyle(text_box_style=tbst,stamp_text=datos_firma,border_width=0)
        else:    
            style=TextStampStyle(text_box_style=tbst,stamp_text=datos_firma, background=PdfImage(cargaimagen.imname),border_width=0,background_opacity=0.4)
        fname = fname.replace('.pdf', '-f.pdf')
        with open(fname, 'wb') as outf:

            out = signers.PdfSigner(signature_meta=signers.PdfSignatureMetadata(
                                                field_name='Sigg1',
                                                reason='Firma',
                                                location='', 
                                                use_pades_lta=True,
                                                subfilter=fields.SigSeedSubFilter.PADES,
                                                embed_validation_info=True,
                                                validation_context=vc
                                                ),
                                signer=FROM_CA_PKCS12,
                                timestamper=None,
                                stamp_style=style,
                                new_field_spec=sp
                                ).sign_pdf(w, output=outf)

        print(nombre,cif)  

    except TypeError:
                    salidaerror=messagebox.askokcancel("ERROR!!!!","Ha habido un error en la firma\n Aségurese de que el fichero                es el correcto y la clave es la correcta")
                    if salidaerror==True:
                        parent.destroy()
    else:
                    salida=messagebox.askokcancel("Fichero firmado","Se ha realizado la firma correctamente\n Se ha guardado el archivo con el mismo nombre + la 'f'")
                    if salida==True:
                        
                        parent.destroy()       `

I have changed my code according to changes in the new release:

  `from certvalidator import ValidationContext` 

 to

 `from pyhanko_certvalidator import ValidationContext` 

Thanks in advance

Support for OpenType fonts with string-keyed CFF outlines

Hey :)

I'm trying to make a script so I can sign my pdfs. As far as I understand from the docs I need a stamp to make it visually obvious that that file is signed.

I assume this is because of %(signer)s in the default stamp-style?
Did I mess something up creating my identity file?

cheers Leo

To Reproduce

openssl req -x509 -newkey rsa:2048 -keyout mykey.pem -out cert.pem -days 365
openssl pkcs12 -export -out identity.p12 -inkey mykey.pem -in cert.pem
pyhanko sign addsig --field Sig1 pkcs12 test.pdf test-sig.pdf identity.p12
pyhanko --config pyhanko.yaml stamp --style-name default --page 1 test-sig.pdf test-sig-stamp.pdf 50 100
2021-12-11 10:33:30,710 - pyhanko.pdf_utils.font.opentype - WARNING - No ROS metadata. Is this really a CIDFont?
2021-12-11 10:33:30,718 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
  File "pyhanko/cli.py", line 80, in pyhanko_exception_manager
    yield
  File "pyhanko/cli.py", line 1247, in stamp
    text_stamp_file(
  File "pyhanko/stamp.py", line 810, in text_stamp_file
    _stamp_file(
  File "pyhanko/stamp.py", line 784, in _stamp_file
    stamp.apply(dest_page, x, y)
  File "pyhanko/stamp.py", line 493, in apply
    stamp_ref = self.register()
  File "pyhanko/stamp.py", line 473, in register
    form_xobj = self.as_form_xobject()
  File "pyhanko/pdf_utils/content.py", line 231, in as_form_xobject
    command_stream = self.render()
  File "pyhanko/stamp.py", line 439, in render
    inner_content = self._render_inner_content()
  File "pyhanko/stamp.py", line 600, in _render_inner_content
    = self._inner_layout_natural_size()
  File "pyhanko/stamp.py", line 587, in _inner_layout_natural_size
    text_commands = self._text_layout()
  File "pyhanko/stamp.py", line 578, in _text_layout
    text = self.style.stamp_text % _text_params
KeyError: 'signer'
Error: Generic processing error.
stamp-styles:
    default:
        type: text
        background: __stamp__
        stamp-text: "Signed by %(signer)s\nTimestamp: %(ts)s"
        text-box-style:
            font: /usr/share/fonts/gnu-free/FreeMono.otf
    noto-qr:
        type: qr
        background: background.png
        stamp-text: "Signed by %(signer)s\nTimestamp: %(ts)s\n%(url)s"
        text-box-style:
            font: NotoSerif-Regular.otf
            leading: 13

Environment

linux 5.15.7-arch1-1
pyHanko, version 0.10.0
Python 3.9.9

Page is ignored when adding fields

Describe the bug
There seems to be a regression between 0.3.0 and 0.4.0 -- version 0.4.0 insists on adding empty signature fields on page 1 of the document, while version 0.3.0 honors command line arguments. Didn't see this fixed when looking through commits, however I did not test current version from git.

Where we find the PKCS#11 config file?

Where we find the config file for configuring the cert label changes/assignment purpose...

Like:

pkcs11-setups:
  test-setup:
    module-path: /usr/lib/libsofthsm2.so
    token-label: testrsa
    cert-label: signer
    user-pin: 1234

Disambiguating certificates in a PCKS#11 token

It is more like a help building code for sign a pdf document using my USB token (self signed certificate).

The signature on output file is corrupted. Im using the test code bellow with your pdf template (minimal-with-field_signed.pdf):

from pyhanko.sign import signers, pkcs11
from pyhanko.sign import timestamps
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter

PKCS11LIB='C:\\Windows\\System32\\eTPKCS11.dll'
SERIALTOKEN=b'xxxxxxxx'
LABEL='xxxxxxxxxxx'
PIN='xxxxxxxxxx'
EXTENSION=".pdf"
DOCUMENT='C:\\Users\\vinicius\\Desktop\\minimal-with-field'
DOCUMENT_EXT=DOCUMENT+EXTENSION
SIGNED_FILE = DOCUMENT+"_signed.pdf"

cms_session = pkcs11.open_pkcs11_session(PKCS11LIB,user_pin=PIN,token_label=LABEL)
cms_signer = pkcs11.PKCS11Signer(cms_session,'')

with open(DOCUMENT_EXT, 'rb') as doc:
    w = IncrementalPdfFileWriter(doc)
    print(w.document_id)
    with open(SIGNED_FILE, 'wb+') as file_out:    
        signers.PdfSigner(signers.PdfSignatureMetadata(field_name='Sig1'),signer=cms_signer).sign_pdf(w,output=file_out)

The code is able to get my certificate data, as the signature (visible text) shows without any trouble, but the signature comes corrupted as shown bellow:

sign_error

btw, nice job with this library! tks in advance

ModuleNotFoundError after fresh installation

Describe the bug
After installing pyHanko on my machine, it's impossible to run it without getting this error:

ModuleNotFoundError: No module named 'pyhanko.sign.ades'

To Reproduce

  1. pip3 install pyHanko
  2. pyhanko

Environment (please complete the following information):

  • OS: Ubuntu 20.04 LTS (WSL)
  • Python: 3.8.5

Additional context
I also tried to do apt-get update/upgrade, it didn't help.
I've added the entire log from the installation and the traceback when running pyhanko
log.txt

Check size estimate

bytes_reserved = test_len + 2 * (test_len // 4)

According to my calculations bytes_reserved ~ 3 * len(test_signature_cms.dump()) and this is not the 50% extra placeholder that was expected.

Proposed solution

            test_len = len(test_signature_cms.dump())          
            # External actors such as timestamping servers can't be relied on to
            # always return exactly the same response, so we build in a 50%
            # error margin (+ ensure that bytes_reserved is even)
            bytes_reserved = test_len * 3 // 4 * 2                 

This problem is in one more place in this file.

The path could not be validated because the end-entity certificate revocation checks failed.

--with-validation-info not working and internet was well connected. (Single document sign validation well working in Adobe Reader)

C:\Users\Satanu\Desktop\signfield>pyhanko --verbose sign addsig --field chairman --with-validation-info --style-name backlogo pkcs11 --p11-setup test-setup Degree1.pdf outputtest1.pdf
2021-07-15 17:59:22,964 - root - DEBUG - Running with --verbose
2021-07-15 17:59:22,965 - root - DEBUG - Finished reading configuration from pyhanko.yml.
2021-07-15 17:59:25,833 - urllib3.connectionpool - DEBUG - Starting new HTTP connection (1): ocvs.pantasign.com:80
2021-07-15 17:59:26,435 - urllib3.connectionpool - DEBUG - http://ocvs.pantasign.com:80 "POST / HTTP/1.1" 200 3298
2021-07-15 17:59:26,452 - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): www.pantasign.com:443
2021-07-15 17:59:27,359 - urllib3.connectionpool - DEBUG - https://www.pantasign.com:443 "GET /repository/PantaSignCRL.crl HTTP/1.1" 200 699013
2021-07-15 17:59:28,714 - pyhanko.cli - ERROR - Error raised while producing signed file.
Traceback (most recent call last):
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko-0.7.0.dev1-py3.9.egg\pyhanko\sign\signers.py", line 2320, in sign_pdf
    signer_cert_validation_path = validator.validate_usage(
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko_certvalidator\__init__.py", line 211, in validate_usage
    self._validate_path()
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko_certvalidator\__init__.py", line 146, in _validate_path
    raise exceptions[0]
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko_certvalidator\__init__.py", line 139, in _validate_path
    validate_path(self._context, candidate_path, self._params)
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko_certvalidator\validate.py", line 70, in validate_path
    return _validate_path(validation_context, path, parameters=parameters)
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko_certvalidator\validate.py", line 592, in _validate_path
    _check_revocation(
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko_certvalidator\validate.py", line 817, in _check_revocation
    raise PathValidationError(pretty_message(
pyhanko_certvalidator.errors.PathValidationError: The path could not be validated because the end-entity certificate revocation checks failed: OCSP response is from after the validation time; CRL is from after the validation time

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko-0.7.0.dev1-py3.9.egg\pyhanko\cli.py", line 74, in pyhanko_exception_manager
    yield
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko-0.7.0.dev1-py3.9.egg\pyhanko\cli.py", line 910, in _sign_pkcs11
    generic_sign_pdf(
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko-0.7.0.dev1-py3.9.egg\pyhanko\cli.py", line 787, in generic_sign_pdf
    result = signers.PdfSigner(
  File "C:\Users\Satanu\AppData\Local\Programs\Python\Python39\lib\site-packages\pyhanko-0.7.0.dev1-py3.9.egg\pyhanko\sign\signers.py", line 2324, in sign_pdf
    raise SigningError(
pyhanko.sign.general.SigningError: ("The signer's certificate could not be validated", PathValidationError('The path could not be validated because the end-entity certificate revocation checks failed: OCSP response is from after the validation time; CRL is from after the validation time'))
Error: Error raised while producing signed file.

Need help.. pls!

setup.py bug

Maybe I do not understand how setup.py works, but I think this diff should be applied.

diff --git a/setup.py b/setup.py
index 14f1ea5..722d2e5 100644
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@ setup(
     packages=[
         'pyhanko',
         'pyhanko.pdf_utils', 'pyhanko.pdf_utils.font',
-        'pyhanko.sign', 'pyhanko.sign.ades',
+        'pyhanko.sign', 'pyhanko.sign.ades', 'pyhanko.sign.signers',
     ],
     url='https://github.com/MatthiasValvekens/pyHanko',
     license='MIT',

The problem is that I failed to install pyhanko master branch using pipenv.

Exception when running `pyhanko sign ltvfix`

Describe the bug
I get an exception when I am trying to run ltvfix on a signed PDF file.

To Reproduce

  1. Get the CA certificate:
    wget https://www.sk.ee/upload/files/TEST_of_EE_Certification_Centre_Root_CA.der.crt
  2. Run the pyhanko ltvfix on the document
    pyhanko sign ltvfix --trust TEST_of_EE_Certification_Centre_Root_CA.der.crt --field Signature1 lorem-ipsum-signed.pdf

Expected behavior

  • Run LTV fix successfully

Environment (please complete the following information):

pyHanko==0.12.0
pyhanko-certvalidator==0.19.4

Additional context

  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/dss.py", line 133, in _cms_objects_to_streams
    yield seen[obj_bytes]
KeyError: [...]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "$VENV/bin/pyhanko", line 8, in <module>
    sys.exit(launch())
  File "$VENV/lib/python3.8/site-packages/pyhanko/__main__.py", line 7, in launch
    cli(prog_name='pyhanko')
  File "$VENV/lib/python3.8/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "$VENV/lib/python3.8/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "$VENV/lib/python3.8/site-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "$VENV/lib/python3.8/site-packages/click/core.py", line 1659, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "$VENV/lib/python3.8/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "$VENV/lib/python3.8/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "$VENV/lib/python3.8/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "$VENV/lib/python3.8/site-packages/pyhanko/cli.py", line 632, in ltv_fix
    output = validation.add_validation_info(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/__init__.py", line 302, in add_validation_info
    return asyncio.run(coro)
  File "/Users/tlilja/.pyenv/versions/3.8.10/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/Users/tlilja/.pyenv/versions/3.8.10/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/dss.py", line 645, in async_add_validation_info
    resulting_dss = DocumentSecurityStore.supply_dss_in_writer(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/dss.py", line 443, in supply_dss_in_writer
    dss.register_vri(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/dss.py", line 215, in register_vri
    crl_refs = set(
  File "$VENV/lib/python3.8/site-packages/pyhanko/sign/validation/dss.py", line 140, in _cms_objects_to_streams
    dest.append(ref)
AttributeError: 'tuple' object has no attribute 'append'

lorem-ipsum-signed.pdf

Cannot modify font-size via yml config file in text stamp style.

Describe the bug
Cannot modify font-size via yml config file in text stamp style.

To Reproduce
To reproduce, use the following yml config.

stamp-styles:
    default:
        type: text
        background: signature.png
        stamp-text: "Signed by %(signer)s\nTimestamp: %(ts)s"
        text-box-style:
            font-size: 32

Note that in this example background: signature.png works perfectly fine and changes the background according to the corresponding file.

Expected behavior
Expected output: the font is increased to 32 from the default value of 10.

Environment (please complete the following information):

  • OS: Windows 10
  • Python 3.8.9
  • PyHanko 0.12.1

merge 2 or 2+ pages into 1 single page

Is there any demo how to merge 2 or 2+ pages into 1 single page like pyPDF2?
I have looked to the folder pyhanko-tests, however, due to I'm not familiar the low level details how the PDF was assmbled, the atempt to add a qr code imgage and a text with link was never success.

Would you please advise the equivalent of pyPDF2 as bellow for pyhanko?

    newPdf = PdfFileReader(buffer)
    filename = os.path.join(path, self.draft)
    existingPdf = PdfFileReader(open(filename, 'rb'))
    page = existingPdf.getPage(0)
    page.mergePage(newPdf.getPage(0))
    output = PdfFileWriter()
    for page in range(existingPdf.getNumPages()):
        output.addPage(existingPdf.getPage(page))
    output.write(buffer)

Converting existing parts of a document to empty signature field

Hi! First of all, this is not an issue with the toolkit itself. So far it works great for my uses. I'd love to see more "alpha quality" code like this... ;)

To the point: I'm currently using a headless LibreOffice to convert a template to final PDF file with some replacements along the way. Problem is, I have to manually "target" coordinates for signature fields with trial and error. Do you have an idea how would I go about automating the process in pyHanko? Number of required signatures is dynamic, so I'm thinking some kind of search & replace type solution here.

Please provide option to add PNG image as signature in the signature widget

Steps I Followed -

add Signature Placeholder
pyhanko sign addfields --field PAGE/X1,Y1,X2,Y2/NAME input.pdf output.pdf

Sign PDF
pyhanko sign addsig --field Sig1 pemder \ --key key.pem --cert cert.pem input.pdf output.pdf

This signs the PDF and create a rectangle with the signature.

But is there a way to add signature image like png there ?

Get hash and hash algorithm of a signed PDF

Describe the solution you'd like
I would like to get the digest and digest algorithm after signing a PDF.

Describe alternatives you've considered
I have tried to get it somehow out of the sign_pdf method, but it only uses local variables... there is probably a way to get it from the signer PDF, but I don't know how to do it.

The CLI switch `--use-pades-lta` should imply `--with-validation-info`

Describe the bug
Currently --use-pades-lta can be (mis)used without --with-validation-info, which runs counter to the intended usage of --use-pades-lta. That's not supposed to be possible.

To Reproduce
See above.

Expected behavior

--use-pades-lta should act as if --with-validation-info was also supplied on the command line.

Screenshots

N/A

Additional context

See discussion #79.

Signing an already signed document changes /MediaBox type from NumberObject to FloatObject

Describe the bug
Signing a already signed PAdES pdf file seems to change the /MediaBox coordinates types from NumberObject to FloatObject, leading to a invalid first signature.

To Reproduce

  1. Using a pdf file signed with external PAdES signer, sign it with pyhanko:
    python -m pyhanko sign addsig --use-pades --field 1/0,0,240,40/SignatureSinc pemder --cert testdata/cert/cert.pem --key testdata/cert/key.pem testdata/test-signed_1.pdf testdata/test-signed_2.pdf
  2. Validate signed file
    python -m pyhanko sign validate --pretty-print testdata/test-signed_2.pdf
    Gives this error:
021-03-09 14:40:38,205 - pyhanko.sign.diff_analysis - WARNING - Error in diff operation between revision 1 and 2
Traceback (most recent call last):
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\sign\diff_analysis.py", line 2067, in review_file
    diff_result = self.apply(
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\sign\diff_analysis.py", line 1967, in apply
    for level, fu in form_changes:
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\sign\diff_analysis.py", line 1211, in apply
    yield from rule.apply(context)
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\sign\diff_analysis.py", line 826, in apply
    yield from qualify(
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\pdf_utils\misc.py", line 218, in map_with_return
    yield func(next(gen))
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\sign\diff_analysis.py", line 1644, in _walk_page_tree_annots
    _compare_dicts(old_kid, new_kid, {'/Annots'})
  File "c:\users\guilhermec\source\repos\assinador\validador\env\src\pyhanko\pyhanko\sign\diff_analysis.py", line 1717, in _compare_dicts
    raise SuspiciousModification(
pyhanko.sign.diff_analysis.SuspiciousModification: Values for dict key /MediaBox differ:[0, 0, 841.92, 595.32] changed to [0, 0, 841.92, 595.32]

And complains about integrity:

Integrity
---------
The signature is cryptographically sound.
The signature does not cover the entire file.
Some modifications may be illegitimate, and they appear to be incompatible with the current document modification policy.

The MediaBox comparison, using DeepDiff module, had dectected the following diferences:

{'type_changes': {'root[0]': {'new_type': <class 'pyhanko.pdf_utils.generic.FloatObject'>,
                              'new_value': 0,
                              'old_type': <class 'pyhanko.pdf_utils.generic.NumberObject'>,
                              'old_value': 0},
                  'root[1]': {'new_type': <class 'pyhanko.pdf_utils.generic.FloatObject'>,
                              'new_value': 0,
                              'old_type': <class 'pyhanko.pdf_utils.generic.NumberObject'>,
                              'old_value': 0}},
 'values_changed': {'root[2]': {'new_value': 841.92, 'old_value': 841.92},
                    'root[3]': {'new_value': 595.32, 'old_value': 595.32}}}

Expected behavior
It should validate the integrity of both signatures:

Screenshots
n/a

Environment (please complete the following information):

  • OS: Windows 10
  • Version 5.0 dev1

Additional context
I am studying adapt pyhanko to validate and sign according with Brazilian standard signed PAdES documents (/SubFilter PBAD-PAdES), that is mostly compatible with ETSI PAdES with minor changes.

0.7 does no recognize token-label

Updating - 9h22min
Now I have something to ruminate. I kept running the same command again and again, trying to figure out what was going on.
Sometimes it would hang up for a long, long time (like 5, 10, 15 minutes) and then come back with the same error message.
But, after some tries, out of the blue, it started working again...
I am mystified, but the fact is that it is working again.
I'll let the issue as reported bellow, but for the time being, IT IS WORKING.

Thank you.

After installing pyhanko 0.7 the command line I've been using for a long time stop working with the following message:

[cut] 
 File "/home/fernando/.local/lib/python3.8/site-packages/pyhanko/cli.py", line 972, in addsig_pkcs11
    with pkcs11.PKCS11SigningContext(pkcs11_config) as signer:
  File "/home/fernando/.local/lib/python3.8/site-packages/pyhanko/sign/pkcs11.py", line 310, in __enter__
    self._session = session = open_pkcs11_session(
  File "/home/fernando/.local/lib/python3.8/site-packages/pyhanko/sign/pkcs11.py", line 72, in open_pkcs11_session
    raise PKCS11Error(
pkcs11.exceptions.PKCS11Error: No token with label FERNANDO JOSE CASTRO CABRAL:12436666687's AC VALID RFB v5 ID found

(I know this is a long and strange label, but that's what worked with previous versions.)

Command line:

pyhanko sign addsig --field "1/250,200,410,300/Fernando Cabral"  --style-name vereador pkcs11 --lib /usr/lib/libaetpkss.so --token-label "FERNANDO JOSE CASTRO CABRAL:12436666687's AC VALID RFB v5 ID" --cert-label "FERNANDO JOSE CASTRO CABRAL:12436666687's AC VALID RFB v5 ID"  "OF047-2021.pdf" "OF047-2021_assinado.pdf"

OS: Linux Mint 20.2, cinnamon edition

Can't install dependencies (PKCS11)

Describe the bug
I can install pyHanko normally, but when trying to install python-pkcs11, I get an error message. I know this isn't completely related to this project, but I've reported the bug here and still haven't got an answer. Is there any other way to make pyHanko work with a RSA PKCS1 Smart Card?

To Reproduce
Try to install python-pkcs11 on a new env.

Expected behavior
Have pyHanko installed along with the needed dependencies.

Environment (please complete the following information):

  • OS: Windows 10 / 11, 64x
  • Python: 3.10
  • pyHanko: 0.11.0

Additional context
I need a way to install python-pkcs11 on a new env, or a way to have pyHanko work with a Smart Card.

'IndirectObject' object is not iterable when using validate_pdf_ltv_signature

My use case is that I want to validate on a server that signatures in certain documents (signed with Adobe Reader) fulfill some specific requirements (comply with PAdES LT or LTA).

This is my fiddle code

with open('extCades_Test document.pdf', 'rb') as doc:
    r = PdfFileReader(doc)
    sig = r.embedded_signatures[0]

    print(sig.signer_cert.subject.native.get('common_name'))
    
    status = validate_pdf_ltv_signature(sig,  
        RevocationInfoValidationType.PADES_LT, 
        key_usage_settings = KeyUsageConstraints(key_usage=set(['digital_signature', 'non_repudiation'])), 
        validation_context_kwargs={'trust_roots': [root_cert2, root_cert, ts_root_cert]})
    print(status.pretty_print_details())

which causes this exception:

Traceback (most recent call last):
  File "c:\Users\ttwellmann\Desktop\byHanko.py", line 55, in <module>
    status = validate_pdf_ltv_signature(sig,
  File "C:\Users\ttwellmann\AppData\Local\Programs\Python\Python38\lib\site-packages\pyhanko\sign\validation.py", line 1511, in validate_pdf_ltv_signature
    dss = DocumentSecurityStore.read_dss(reader)
  File "C:\Users\ttwellmann\AppData\Local\Programs\Python\Python38\lib\site-packages\pyhanko\sign\validation.py", line 1924, in read_dss
    for cert_ref in dss_dict.get('/Certs', ()):
TypeError: 'IndirectObject' object is not iterable

The signature in the text document is level B-LT, has an external timestamp and was created with Adobe Reader DC.

Expected behavior
I would have expected that the function returns information about any missing information in the signature, but not an exception
.
Environment (please complete the following information):
Window 10, python 3.8.x, pyHanko 0.4.0

Additional context
I

Parse error in fetched certificate propagates to CLI

pyhanko sign addsig --field signature1 --with-validation-info --use-pades pkcs12 output.pdf signed.pdf emudhra.pfx --passfile password.txt

this above is the whole command.

which produces the following error.

`2021-12-04 18:54:37,804 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 145, in queue_fetch_task
wait_event: asyncio.Event = running_jobs[tag]
KeyError: 'http://www.e-mudhra.com/repository/cacerts/doccl2.crt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/pyhanko/cli.py", line 80, in pyhanko_exception_manager
yield
File "/usr/local/lib/python3.9/site-packages/pyhanko/cli.py", line 831, in addsig_simple_signer
generic_sign_pdf(
File "/usr/local/lib/python3.9/site-packages/pyhanko/cli.py", line 841, in generic_sign_pdf
result = signers.PdfSigner(
File "/usr/local/lib/python3.9/site-packages/pyhanko/sign/signers/pdf_signer.py", line 1220, in sign_pdf
result = asyncio.run(
File "/usr/local/Cellar/[email protected]/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/local/Cellar/[email protected]/3.9.7_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/usr/local/lib/python3.9/site-packages/pyhanko/sign/signers/pdf_signer.py", line 1272, in async_sign_pdf
await signing_session.perform_presign_validation(pdf_out)
File "/usr/local/lib/python3.9/site-packages/pyhanko/sign/signers/pdf_signer.py", line 1419, in perform_presign_validation
signer_path = await self._perform_presign_signer_validation(
File "/usr/local/lib/python3.9/site-packages/pyhanko/sign/signers/pdf_signer.py", line 1476, in _perform_presign_signer_validation
await validator.async_validate_usage(key_usage)
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/init.py", line 283, in async_validate_usage
await self._validate_path()
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/init.py", line 127, in _validate_path
paths = await self._context.certificate_registry.async_build_paths(
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/registry.py", line 425, in async_build_paths
await self._walk_issuers(path, paths, failed_paths)
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/registry.py", line 477, in _walk_issuers
async for issuer in self.fetcher.fetch_cert_issuers(path.first):
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 69, in fetch_cert_issuers
fetched_certs = await self.fetch_certs(
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 56, in fetch_certs
return await self._perform_fetch(url, task)
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/util.py", line 37, in _perform_fetch
return await queue_fetch_task(
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 176, in queue_fetch_task
return _return_or_raise(result)
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 181, in _return_or_raise
raise result
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 163, in queue_fetch_task
result = await async_fun()
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/requests_fetchers/cert_fetch_client.py", line 55, in task
return list(results)
File "/usr/local/lib/python3.9/site-packages/pyhanko_certvalidator/fetchers/common_utils.py", line 38, in unpack_cert_content
yield x509.Certificate.load(response_data)
File "/usr/local/lib/python3.9/site-packages/asn1crypto/core.py", line 230, in load
value, _ = _parse_build(encoded_data, spec=spec, spec_params=kwargs, strict=strict)
File "/usr/local/lib/python3.9/site-packages/asn1crypto/core.py", line 5672, in _parse_build
return (_build(*info, spec=spec, spec_params=spec_params), new_pointer)
File "/usr/local/lib/python3.9/site-packages/asn1crypto/core.py", line 5568, in _build
raise ValueError(unwrap(
ValueError: Error parsing asn1crypto.x509.Certificate - tag should have been 16, but 13 was found
Error: Generic processing error.`

Generic processing error: invalid literal for int() with base 10: b'f'

Describe the bug
Error on file parsing during validation of signed file.

>python -mpyhanko sign validate --pretty-print testdata\assinado_com_web_socket.pdf
2021-05-21 17:00:19,316 - pyhanko.cli - ERROR - Generic processing error.
Traceback (most recent call last):
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\cli.py", line 69, in pyhanko_exception_manager
    yield
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\cli.py", line 421, in validate_signatures
    r = PdfFileReader(infile)
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\pdf_utils\reader.py", line 605, in __init__
    self.read()
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\pdf_utils\reader.py", line 940, in read
    self._read_xrefs()
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\pdf_utils\reader.py", line 875, in _read_xrefs
    startxref = self._read_xref_stream()
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\pdf_utils\reader.py", line 825, in _read_xref_stream
    idnum, generation = read_object_header(stream, strict=self.strict)
  File "C:\Users\guilhermec\source\repos\pyHanko\pyhanko\pdf_utils\reader.py", line 447, in read_object_header
    return int(idnum), int(generation)
ValueError: invalid literal for int() with base 10: b'f'
Error: Generic processing error.

To Reproduce
python -mpyhanko sign validate --pretty-print testdata\assinado_com_web_socket.pdf
assinado_com_web_socket.pdf

Expected behavior
File should be invalid, unless added the AC file to the trusted file

Environment (please complete the following information):

  • OS: Windows 10 and Ubuntu 20.10, python 3.9.5
  • Version: current HEAD

How to distinguish signature and timestamp during validation

I have a PDF with a signature (with an external timestamp) and a separate second timestamp (for the purpose of LTA compliance). I want to validate all embedded signatures with validate_pdf_signature(..).

reader.embedded_signatures is in this case a list of two objects.

The validation works fine for the first signature, but when the function is applied to the separate timestamp the following exception is raised:

File "C:\Users\digisig-service\Desktop\SigningCenter\manager\signature.py", line 35, in validateAllSignatures
status = validate_pdf_signature(signature,
File "C:\Program Files\Python38\lib\site-packages\pyhanko-0.6.0.dev1-py3.8.egg\pyhanko\sign\validation.py", line 1201, in validate_pdf_signature
raise SignatureValidationError("Signature object type must be /Sig")
pyhanko.sign.general.SignatureValidationError: Signature object type must be /Sig

It seems that the function should/can only be applied to embedded signatures that are actually true signatures. But how can I check if an EmbeddedPDFSignature object is a true signature or just a simple timestamp that should not be used as input to validate_pdf_signature(..)? Or should validate_pdf_signature(..) actually also work correctly with timestamps?

Best regards
Thorsten

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.