NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1738 most downloaded on PyPI
Tools for stamping and signing PDF files
Last release 1 months ago
31 Aug 2026
Ships fairly regularly
a new release about every 5 weeks
Nearly every release is documented
notes for 58 of 58 stable releases
1 version withdrawn
withdrawn after publishing
6 years old
59 releases · first in 2020
One column per quarter.
The release artifacts have been published to PyPI . Documentation is available on ReadTheDocs .
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.37.0 release are available on the Release History page
Release date: 2026-09-01
requests was relegated to the optional dependency group [requests] due to the change in default fetching backends (see below).
Deprecate fallback to OS trust list through oscrypto .
Remove long-standing deprecated APIs
Signer.sign , Signer.sign_prescribed_attributes , Signer.sign_general_data
validate_cms_signature , validate_detached_cms
PdfSigner.digest_doc_for_signing
open_pkcs11_session(token_label=...)
find_cms_attribute
The HTTPTimeStamper reshuffle (see below) should not be a breaking change for most users, but code that relies on subclassing these objects will likely need some attention.
aiohttp was moved to the default dependency list. requests was relegated to the optional dependencies (see below). The [async-http] optional dependency group was kept around to avoid breaking dependency resolution downstream, but is now empty.
Let FileSystemTLCache accept a str path.
Make aiohttp the default backend for fetching validation data and timestamp tokens
HTTPTimeStamper absorbs AIOHttpTimeStamper , which becomes a deprecated
subclass.
Requests-based version renamed to RequestsHTTPTimeStamper .
Make aiohttp resource management more hands-off.
Resolve /Parent and mark ancestors when inserting a page.
Specify encoding="utf-8" on all text file reads.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.36.2 release are available on the Release History page
Release date: 2026-07-27
Prevent new signature fields from reusing old signature objects during difference analysis.
Release date: 2026-07-27
Prevent new signature fields from reusing old signature objects during difference analysis.
The release artifacts have been published to PyPI . Documentation is available on ReadTheDocs .
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.36.1 release are available on the Release History page
Release date: 2026-07-26
No functional changes, this release adopts the new attestation strategy .
Release date: 2026-07-26
No functional changes, this release adopts the new attestation strategy.
The release artifacts have been published to PyPI . Documentation is available on ReadTheDocs .
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.36.0 release are available on the Release History page
Release date: 2026-07-25
Bump the minimal signxml version to 5.1.0 (in the [etsi] group) to accommodate its point-in-time validation API.
Relax upper bound for uharfbuzz to <0.56.0 .
Drop the direct dependency on pyyaml , which was no longer used.
Support signing with ML-DSA through the PKCS#11 signer.
Realign the EU List of Trusted Lists anchor after its recent re-anchoring by OJEU publication, and allow bootstrapping against a specific anchor.
Improve error messages for invalid trusted-list signatures.
Mass-apply linting fixes to comply with new ruff default ruleset.
Tolerate space-padded offsets in classic cross-reference tables in non-strict mode, and raise an explicit error for invalid xref operation markers in strict mode.
Provide clearer errors when parsing malformed numbers in cross-reference tables.
Fix unintended use of naive datetime in digest algorithm policy check.
Fix Configurable field introspection for PEP 604 union annotations.
The release artifacts have been published to PyPI . Documentation is available on ReadTheDocs .
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.35.2 release are available on the Release History page
Release date: 2026-07-05
Relax upper bound for aiohttp to <3.15 .
Fix ISO 32000-1 §7.4.2 odd-digit handling in ASCIIHexDecode .
Handle fields with /AS in difference analysis.
Drop unsupported subfilters while enumerating signature fields, i.e. before validation.
Sync font size between style and FontEngine . This also promotes the font_size field to FontEngine .
When parsing XMP, auto-promote URIs serialised as text properties to URI status when they appear as text in an XML element. That was already the case for XML attributes; this change generalises the existing behaviour.
When parsing XMP, make sure that XML attributes that are part of RDF/XML meta-syntax are not accidentally treated as semantic property attributes at the XMP level.
Release date: 2026-07-05
Relax upper bound for aiohttp to <3.15.
Fix ISO 32000-1 §7.4.2 odd-digit handling in ASCIIHexDecode.
Handle fields with /AS in difference analysis.
Drop unsupported subfilters while enumerating signature fields, i.e. before validation.
Sync font size between style and ~pyhanko.pdf_utils.font.api.FontEngine. This also promotes the font_size field to ~pyhanko.pdf_utils.font.api.FontEngine.
When parsing XMP, auto-promote URIs serialised as text properties to URI status when they appear as text in an XML element. That was already the case for XML attributes; this change generalises the existing behaviour.
When parsing XMP, make sure that XML attributes that are part of RDF/XML meta-syntax are not accidentally treated as semantic property attributes at the XMP level.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.35.1 release are available on the Release History page
Release date: 2026-05-06
Bump cryptography to 48.0.0 .
Relax upper bound for uharfbuzz to <0.55.0 .
Allow signing with ML-DSA
Allow validating ML-DSA signatures
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.35.0 release are available on the Release History page
Release date: 2026-05-03
Remove support for deprecated LTV validation functionality. Call sites must be updated to use the AdES validation engine .
Several low-level API changes in generic_cms to allow refactoring the timestamp handling code.
extract_tst_data() was removed.
compute_signature_tst_digest() was removed.
Several functions that previously took a digest to validate against have been changed to take a (str) -> bytes callable.
Bump cryptography to 47.0.0 .
Relax upper bound on pytest-cov to <7.2 .
Relax upper bound on certomancer to <0.15 .
Introduce certifi as a mandatory dependency for testing.
Properly support harvesting PoE from multiple signature/content timestamps in the same signature container.
For the purposes of validation status reporting: if there are multiple signature timestamps, accept any one that passes validation (this is appropriate since the main value of timestamps is evidentiary). At some point in the future, we may want to add a way to report on the status of all timestamps>
Add revinfo archival data to local knowledge.
Restructure algorithm policy handling. Algorithm policy errors will typically not bubble up outside the validation engine anymore, but will instead be reflected in the validation status.
Replace FreeSerif usage in tests with SourceSerif
Tweak MediaBox retrieval.
Fix /AP positioning on field creation.
Fix annot dict not being re-serialised on signing when split from form dictionary.
Improve error handling in parse_pdf_date .
Fix handling of PoE requirements in past validation data.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.34.1 release are available on the Release History page
Release date: 2026-03-08
Address a packaging error with tests directory in sdists.
Release date: 2026-03-08
Address a packaging error with tests directory in sdists.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.34.0 release are available on the Release History page
Release date: 2026-03-05
Drop support for Python 3.9
Relax upper bound on xsdata to <27.0 .
Include tests in sdists again, and graft common testing tooling onto the sdists so they can be tested in a self-contained way.
Fix signed attribute enumeration in AdES report.
FieldMDP INCLUDE/EXCLUDE incorrectly locking fields with shared name prefix.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.33.0 release are available on the Release History page
Release date: 2026-02-08
Fix inconsistent aiohttp version bounds.
Relax uharfbuzz upper bound to <0.54.0 .
Bump python-barcode to ==0.16.1 .
Explicitly define a no-op stamping style
Integrate some actual signing hardware into CI processes.
Use embedded intermediate certificates when validating existing timestamps.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.32.0 release are available on the Release History page
Release date: 2025-11-22
Support Python 3.14
Relax uharfbuzz upper bound to <0.51.0 .
Warning
PyHanko currently does not test against free-threaded Python builds. Feel free to raise issues related to free-threaded Python in the discussion forum or on the issue tracker if you’re sure the problem is pyHanko-related, but there are currently no concrete plans to actively pursue support for this.
Support reading PKCS#12 data from memory.
Make PKCS#11 sign_kwargs easier to customise in subclasses.
Support basic text field filling.
Put in place scaffolding for content stream parsing.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.31.0 release are available on the Release History page
Release date: 2025-09-12
Some pieces of the configuration API were refactored or pushed fully into the CLI layer.
The old LTV validation functionality provided by async_validate_pdf_ltv_signature() has now been deprecated and may be removed in a future release.
Release date: 2025-09-12
Some pieces of the configuration API were refactored or pushed fully into the CLI layer.
The old LTV validation functionality provided by ~pyhanko.sign.validation.ltv.async_validate_pdf_ltv_signature has now been deprecated and may be removed in a future release.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.30.0 release are available on the Release History page
Release date: 2025-08-23
Bump python-pkcs11 to 0.9.x .
Introduce signxml>=4.2.0 into [etsi] dependency group.
Allow custom text and stamp border colours.
Allow slotting in a custom validation implementation (e.g. to support validating signatures that require cryptographic primitives that aren’t supported in-tree). This applies to certificate validation as well. See SignatureValidator .
Add support for validating against ETSI TS 119 612 trusted lists (as used in the EU’s eIDAS programme) and deriving qualification judgments from such lists for signatures and timestamps. This is an incubating feature; in particular it is not yet exposed in the CLI.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.29.1 release are available on the Release History page
Release date: 2025-06-20
Bump python-pkcs11 to 0.8.0 .
Relax aiohttp upper bound to allow 3.12.x and make sure we test against the most recent version.
Correct buggy behaviour when reauthenticating with a security handler.
Fix registration of multiple extensions in encrypted files.
Tolerate key usage violations when the signer is a trust anchor.
Remove unnecessary 3.8 compatibility code.
Make it easier to customise PKCS#11 queries
Note: As indicated in the release notes, the CLI was split off from the core library into a separate PyPI artifact. This release also comes with sever
Note: As indicated in the release notes, the CLI was split off from the core library into a separate PyPI artifact. This release also comes with several other significant dependency changes.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.29.0 release are available on the Release History page
Release date: 2025-05-27
The pyhanko.keys and pyhanko.stamp modules were turned into packages, exposing the same API in their respective init.py , so this change is source-compatible.
The version and version_info attributes are no longer exposed at the root package level, but have been moved into pyhanko.version (which was also turned into a subpackage).
The CLI code still installs as pyhanko.cli in the package hierarchy.
There are no code-level changes for CLI plugins other than the requirement to add a dependency on pyhanko-cli . In principle, this allows “old” plugins to keep working without needing a re-release as long as pyhanko-cli is installed together with pyhanko .
Make the dependency on qrcode optional (in the new [qr] dependency group)
Replace defusedxml with a dependency on lxml , configured appropriately. This was done in anticipation of some future feature work that will require a dependency on lxml either way.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.28.0 release are available on the Release History page
Release date: 2025-05-24
Drop support for Python 3.8
Retool repository structure as uv multi-project workspace.
Include pyhanko-certvalidator as subproject.
Remove dev-only & testing dependencies from package metadata.
Fix error in SHA-3 detection when determining whether to include the ISO/TS 32001 extension metadata.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.27.1 release are available on the Release History page
Release date: 2025-05-14
Reinstated support for decrypting files using public-key encryption where 3DES or RC2 are used as the envelope encryption algorithm. The new integration uses pyca/cryptography ’s decrepit subpackage instead of oscrypto .
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.27.0 release are available on the Release History page
Release date: 2025-05-12
Relax uharfbuzz upper bound to <0.51.0 .
Constrain click to <8.2.0 while we address breaking changes.
Bump test dependencies.
Allow choosing whether to apply stamps in the page’s default coordinate system, or in the frame of reference that is active at the end of the page’s content stream. The former is now the default.
Fix handling of “plugin unavailable” error.
Clear /NeedAppearances when putting in a signature.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.26.0 release are available on the Release History page
Release date: 2025-03-08
Some outdated algos for encrypting the security handler seed in a public-key encrypted PDF were dropped to get rid of oscrypto as a direct dependency of pyhanko . It is still pulled in via pyhanko-certvalidator , but it is no longer used for any cryptographic operations (which is significant, because of compatibility issues on systems that no longer ship OpenSSL 1.1.1)
Relax uharfbuzz upper bound to <0.47.0 .
Make defusedxml a regular dependency, remove [xmp] dependency group.
Remove [extra-pubkey-algs] dependency group (see breaking change list)
Expose signature_mechanism parameter in PKCS#11 API.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.25.3 release are available on the Release History page
Release date: 2024-11-17
Workflow dependency bumps
Set aiohttp upper bound to 3.12
Bump pyhanko-certvalidator to 0.26.5
Bump certomancer to 0.12.3
Note: these changes make pyHanko compatible with the (unreleased) API change in asn1crypto #230 , which is nevertheless already being shipped in some distros.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.25.2 release are available on the Release History page
Release date: 2024-11-11
Bump minimal cryptography version to 43.0.3 .
Update uharfbuzz upper bound to 0.42.0 .
Add Python 3.13 to the package metadata & include it in CI.
Some test dependencies bumped.
Properly propagate strict=False in post-signing instructions.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.25.1 release are available on the Release History page
Release date: 2024-07-18
Align usage of SHAKE256 OIDs with Ed448 with RFC 8419
Release date: 2024-07-18
Align usage of SHAKE256 OIDs with Ed448 with RFC 8419
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.25.0 release are available on the Release History page
Release date: 2024-05-06
Implement ISO/TS 32003 and ISO/TS 32004, to support AES-GCM streams and MAC authentication in encrypted PDF 2.0 documents, respectively. MACs are turned on by default when creating documents with PDF 2.0-style encryption.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.24.0 release are available on the Release History page
Release date: 2024-04-27
Setting & retrieving permission flags for encrypted files now comes with an ergonomic API that is much less error-prone. You no longer have to manually convert your permission bits to their signed integer representation. See pyhanko.pdf_utils.crypt.permissions .
Upgraded xsdata (optional) to 24.4 .
Several issues with copying objects from encrypted documents (in particular, encrypted documents with signatures) have been fixed.
Tolerate unpadded empty ciphertext.
Improve error messages on malformed keys.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.23.2 release are available on the Release History page
Release date: 2024-03-25
Upgraded certomancer dependency for tests to 0.12.0 .
Upgraded pytest-asyncio tot 0.23.6 .
Fix handling of “OAEP preferred” flag when encrypting documents with a public key.
Fix endianness issue when reading & writing permissions in documents encrypted with a public key.
Tolerate AcroForm**s without a **Fields entry.
Increase resilience against issues with oscrypto .
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.23.1 release are available on the Release History page
Release date: 2024-03-14
Fix a regression in the way PKCS#11 objects are loaded.
Release date: 2024-03-14
Fix a regression in the way PKCS#11 objects are loaded.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.23.0 release are available on the Release History page
Release date: 2024-03-10
The BeID signer implementation and CLI command was moved into a separate package; see pyhanko-beid-plugin . While this integration was so far preserved in the core tree for historical reasons, pyHanko has matured beyond this kind of vendor/country-specific code. Note that CLI invocations will continue to work unchanged as long as pyhanko-beid-plugin is installed alongside pyHanko, thanks to Python’s package entry point mechanism.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.22.0 release are available on the Release History page
Release date: 2024-03-07
Relax upper bounds on xsdata and uharfbuzz .
cryptography` to ``42.0.1
Get rid of pytest-runner
Relax processing of PKCS#11 options, setting better defaults so users have to write less config to select their key/certificate. (see PR #296 )
Add timestamp command to CLI to add a document timestamp without performing any PAdES validation.
Gracefully handle lack of /Type entry in signature objects vailidation.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.21.0 release are available on the Release History page
Release date: 2023-11-26
Bumped the minimal supported Python version to 3.8 (dropping 3.7).
Bumped the lower bound on qrcode to 7.3.1 .
Bumped pyhanko-certvalidator to 0.26.x .
Bumped the lower bound on click to 8.1.3 .
Bumped the lower bound on requests to 2.31.0 .
Bumped the lower bound on pyyaml to 6.0 .
Bumped the lower bound on cryptography to 41.0.5 .
Bumped aiohttp to 3.9.x .
Bumped certomancer-csc-dummy test dependency to 0.2.3 .
Introduced new dependency group etsi with xsdata for features implementing functionality from AdES and related ETSI standards.
Add support for /ContactInfo , /Prop_AuthTime and /Prop_AuthType .
Experimental support for AdES validation reports (requires new etsi optional deps)
New API function for simulating PAdES-LTA validation at a time in the future; see simulate_future_ades_lta_validation() .
Add support for asserting the nonrevoked status of a certificate chain.
Add --resave flag to addfields subcommand.
Fixed an oversight in the serialisation of the /ByteRange entry in a signature that prevented large documents from being signed correctly.
Various adjustments to the (still experimental) AdES validation API.
Various local documentation fixes.
PDF signatures that do not omit the eContent field in their encapsulated content info are now rejected as invalid.
Include PyPDF2 licence file in package metadata.
Cleaned up loading logic in PdfFileReader . The most important impact of this change is that structural errors in the encryption dictionary will now cause exceptions to be thrown when decryption is attempted, not in the init function.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.20.1 release are available on the Release History page
Release date: 2023-09-17
Upgrade pyhanko-certvalidator to 0.24.x
Tolerate missing D: in date strings (see PR #296 ).
Various minor documentation improvements.
Release workflow dependency bumps and minor improvements.
Release date: 2023-09-17
Upgrade pyhanko-certvalidator to 0.24.x
Tolerate missing D: in date strings (see PR #296).
Various minor documentation improvements.
Release workflow dependency bumps and minor improvements.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.20.0 release are available on the Release History page
Release date: 2023-07-28
Relax upper bound on uharfbuzz to <0.38.0 (allows more users to benefit from prebuilt wheels)
Bump python-barcode from 0.14.0 to 0.15.1 .
Bump pytest-asyncio from 0.21.0 to 0.21.1 .
Relax pytest-cov bound to allow 4.1.x
Various minor documentation improvements.
Improved unit test coverage, especially for error handling.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.19.0 release are available on the Release History page
Release date: 2023-06-18
Bump pyhanko-certvalidator to 0.23.0
certomancer updated to 0.11.0 , certomancer-csc-dummy to 0.2.2
Minor reorganisation of the EnvelopeKeyDecrypter . The change moves the cert property from an attribute to an abstract property, and adds a method to allow us to handle protocols based on key agreement in addition to key transport. Implementations need not implement both.
Move ignore_key_usage into to new RecipientEncryptionPolicy class.
Support RSAES-OAEP for file encryption with the public-key security handler. This is not widely supported by PDF viewers in the wild.
Support some ECDH-based key exchange methods for file encryption with the public-key security handler. Concretely, pyHanko now supports the dhSinglePass-stdDH-sha*kdf family from RFC 5753, which is also implemented in Acrobat (for NIST curves). X25519 and X448 are also included.
Better UX for argument errors relating to visible signature creation.
Allow processing OCSP responses without nextUpdate .
Run non-cryptographic CLI commands in nonstrict mode.
Treat nulls the same as missing entries in dictionaries, as required by the standard.
Fix several default stamp style selection issues in CLI
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release artifacts have been published to PyPI. Documentation is available on ReadTheDocs.
The release notes for the 0.18.1 release are available on the Release History page
Release date: 2023-04-29
Remove dependency on pytz with fallback to backports.zoneinfo
Bump tzlocal version to 4.3 .
Do not rely on deprecated timezone API anymore in the tests. See PR #257 .
Release date: 2023-04-29
Remove dependency on pytz with fallback to backports.zoneinfo
Bump tzlocal version to 4.3.
Do not rely on deprecated timezone API anymore in the tests. See PR #257.
The release will be published to PyPI. Documentation is available on ReadTheDocs.
The release will be published to PyPI. Documentation is available on ReadTheDocs.
Important remark: This is the first pyHanko release to make use of GitHub Actions to publish and sign release artifacts. The CI signing workflow uses Sigstore to bind the published artifacts to pyHanko's "GitHub identity", as it were. For the time being, releases will continue to be manually signed with GPG in addition. My PGP key fingerprint is 9C41 44F3 5E74 2C88 A5D2 563C 15F4 2BEF A159 BA54, the same as for previous releases.
Should you want to validate the .sigstore signature bundles, download all the artifacts into a single folder, install sigstore from pip and run the following command:
sigstore verify github \
--cert-identity https://github.com/MatthiasValvekens/pyHanko/.github/workflows/release.yml@refs/tags/v0.18.0 \
pyHanko*.tar.gz pyHanko*.whl
Note: This release also marks pyHanko’s move to beta status. That doesn’t mean that it’s feature-complete in every respect, but it does mean that we’ve now entered a stabilisation phase in anticipation of the 1.0.0 release, so until then the focus will be on fixing bugs and clearing up issues in the documentation (in particular regarding the API contract). After the 1.0.0 release, pyHanko will simply follow SemVer.
The release notes for the 0.18.0 release are available here.
Release date: 2023-04-26
This is largely a maintenance release in the sense that it adds relatively little in the way of core features, but it nevertheless comes with some major reorganisation and work to address technical debt.
This release also marks pyHanko’s move to beta status. That doesn’t mean that it’s feature-complete in every respect, but it does mean that we’ve now entered a stabilisation phase in anticipation of the 1.0.0 release, so until then the focus will be on fixing bugs and clearing up issues in the documentation (in particular regarding the API contract). After the 1.0.0 release, pyHanko will simply follow SemVer.
Some changes have been made to the Signer class. For all practical purposes, these are mostly relevant for custom Signer implementations. Regular users should see fairly little impact.
The arguments to init have been made keyword-only.
Several attributes have been turned into read-only properties:
signing_cert
cert_registry
attribute_certs
signature_mechanism
This change was made to better reflect the way the properties were used internally, and made it easier to set expectations for the API: it doesn’t make sense to allow arbitrary modifications to these properties for all Signer implementations. The parameters to init have been extended to allow setting defaults more cleanly. Implementation-wise, the properties are backed by an underscored internal variable (e.g. _signing_cert for signing_cert ). Subclasses can of course still elect to make some of these read-only properties writable by declaring setters.
get_signature_mechanism was renamed to get_signature_mechanism_for_digest() to make it more clear that it does more than just fetch the underlying value of signature_mechanism .
Concretely, this means that init logic of the form
class MySigner ( Signer ): def init ( self , signing_cert : x509 . Certificate , cert_registry : CertificateStore , * args , ** kwargs ): self . signing_cert = signing_cert self . cert_registry = cert_registry self . signature_mechanism = signature_mechanism super () . init ()
needs to be rewritten as
class MySigner ( Signer ): def init ( self , signing_cert : x509 . Certificate , cert_registry : CertificateStore , * args , ** kwargs ): self . _signing_cert = signing_cert self . _cert_registry = cert_registry self . _signature_mechanism = signature_mechanism super () . init ()
or, alternatively, as
class MySigner ( Signer ): def init ( self , signing_cert : x509 . Certificate , cert_registry : CertificateStore , * args , ** kwargs ): super () . init ( signing_cert = signing_cert , cert_registry = cert_registry , signature_mechanism = signature_mechanism )
Other than these, there have been some miscellaneous changes.
The CLI no longer allows signing files encrypted using public-key encryption targeted towards the signer’s certificate, because that feature didn’t make much sense in key management terms, was rarely used, and hard to integrate with the new plugin system.
APIs with status_cls parameters have made certain args keyword-only for strict type checking purposes.
Move add_content_to_page to add_to_page() to deal with a (conceptual) circular dependency between modules.
CertificateStore is no longer reexported by pyhanko.sign.general .
The BEIDSigner no longer allows convenient access to the authentication certificate.
Packaging-wise, underscores have been replaced with hyphens in optional dependency groups.
In pyhanko_certvalidator , InvalidCertificateError is no longer a subclass of PathValidationError .
Finally, some internal refactoring took place as well:
The cli.py module was refactored into a new subpackage ( pyhanko.cli ) and is now also tested systematically.
CLI config classes have been refactored, some configuration was moved to the new pyhanko.config package.
Time tolerance config now passes around timedelta objects instead of second values.
The qualify() function in the difference analysis has been split into qualify() and qualify_transforming() .
Certificate and key loading was moved to a new pyhanko.keys module, but pyhanko.sign.general still reexports the relevant functions for backwards compatibility. Concretely, the affected functions are
pyhanko.keys.load_cert_from_pemder() ,
pyhanko.keys.load_certs_from_pemder() ,
pyhanko.keys.load_certs_from_pemder_data() ,
pyhanko.keys.load_private_key_from_pemder() ,
pyhanko.keys.load_private_key_from_pemder_data() .
Onboarded mypy and flag pyHanko as a typed library by adding py.typed .
Package metadata and tooling settings have now been centralised to pyproject.toml . Other configuration files like setup.py , requirements.txt and most tool-specific config have been eliminated.
The docstring-based documentation for pyhanko_certvalidator was added to the API reference.
Some non-autogenerated API reference documentation pages were consolidated to reduce the sprawl.
Heavily reworked the CI/CD pipeline. PyHanko releases are now published via GitHub Actions and signed with Sigstore. GPG signatures will continue to be provided for the time being.
Bump pyhanko-certvalidator to 0.22.0 .
Relax the upper bound on uharfbuzz for better Python 3.11 support
The AdES LTA validator now tolerates documents that don’t have a DSS (assuming that all the required information is otherwise present).
Ensure that the trusted attribute on SignatureStatus is not set if the validation path is not actually available.
Correct the typing on validation_path .
Fix several result presentation bugs in the AdES code.
Fix overeager sharing of POEManager objects in AdES code.
Correct algo policy handling in AdES-with-time validation.
Ensure that container_ref is also populated on past versions of the trailer dictionary.
The CLI now features plugins ! All current addsig subcommands have been reimplemented to use the plugin interface. Other plugins will be auto-detected through package entry points.
Refine algorithm policy handling; put in place a subclass of AlgorithmUsagePolicy specifically for CMS validation; see CMSAlgorithmUsagePolicy .
Try to remember paths when validation fails.
Make certificates from local CMS context available during path building for past certificate validation (subject to PoE checks).
Move docmdp_ok up in the hierarchy to ModificationInfo .
Release date: 2023-04-26
This is largely a maintenance release in the sense that it adds relatively little in the way of core features, but it nevertheless comes with some major reorganisation and work to address technical debt.
This release also marks pyHanko's move to beta status. That doesn't mean that it's feature-complete in every respect, but it does mean that we've now entered a stabilisation phase in anticipation of the 1.0.0 release, so until then the focus will be on fixing bugs and clearing up issues in the documentation (in particular regarding the API contract). After the 1.0.0 release, pyHanko will simply follow SemVer.
Some changes have been made to the ~pyhanko.sign.signers.pdf_cms.Signer class. For all practical purposes, these are mostly relevant for custom ~pyhanko.sign.signers.pdf_cms.Signer implementations. Regular users should see fairly little impact.
The arguments to __init__ have been made keyword-only.
Several attributes have been turned into read-only properties:
~pyhanko.sign.signers.pdf_cms.Signer.signing_cert
~pyhanko.sign.signers.pdf_cms.Signer.cert_registry
~pyhanko.sign.signers.pdf_cms.Signer.attribute_certs
~pyhanko.sign.signers.pdf_cms.Signer.signature_mechanism
This change was made to better reflect the way the properties were used internally, and made it easier to set expectations for the API: it doesn't make sense to allow arbitrary modifications to these properties for all ~pyhanko.sign.signers.pdf_cms.Signer implementations. The parameters to __init__ have been extended to allow setting defaults more cleanly. Implementation-wise, the properties are backed by an underscored internal variable (e.g. _signing_cert for signing_cert). Subclasses can of course still elect to make some of these read-only properties writable by declaring setters.
get_signature_mechanism was renamed to ~pyhanko.sign.signers.pdf_cms.Signer.get_signature_mechanism_for_digest to make it more clear that it does more than just fetch the underlying value of ~pyhanko.sign.signers.pdf_cms.Signer.signature_mechanism.
Concretely, this means that init logic of the form
class MySigner(Signer):
def __init__(
self,
signing_cert: x509.Certificate,
cert_registry: CertificateStore,
*args, **kwargs
):
self.signing_cert = signing_cert
self.cert_registry = cert_registry
self.signature_mechanism = signature_mechanism
super().__init__()
needs to be rewritten as
class MySigner(Signer):
def __init__(
self,
signing_cert: x509.Certificate,
cert_registry: CertificateStore,
*args, **kwargs
):
self._signing_cert = signing_cert
self._cert_registry = cert_registry
self._signature_mechanism = signature_mechanism
super().__init__()
or, alternatively, as
class MySigner(Signer):
def __init__(
self,
signing_cert: x509.Certificate,
cert_registry: CertificateStore,
*args, **kwargs
):
super().__init__(
signing_cert=signing_cert,
cert_registry=cert_registry,
signature_mechanism=signature_mechanism
)
Other than these, there have been some miscellaneous changes.
The CLI no longer allows signing files encrypted using public-key encryption targeted towards the signer's certificate, because that feature didn't make much sense in key management terms, was rarely used, and hard to integrate with the new plugin system.
APIs with status_cls parameters have made certain args keyword-only for strict type checking purposes.
Move add_content_to_page to ~pyhanko.pdf_utils.content.PdfContent.add_to_page to deal with a (conceptual) circular dependency between modules.
~pyhanko_certvalidator.registry.CertificateStore is no longer reexported by pyhanko.sign.general.
The BEIDSigner no longer allows convenient access to the authentication certificate.
Packaging-wise, underscores have been replaced with hyphens in optional dependency groups.
In pyhanko_certvalidator, ~pyhanko_certvalidator.errors.InvalidCertificateError is no longer a subclass of ~pyhanko_certvalidator.errors.PathValidationError.
Finally, some internal refactoring took place as well:
The cli.py module was refactored into a new subpackage (pyhanko.cli) and is now also tested systematically.
CLI config classes have been refactored, some configuration was moved to the new pyhanko.config package.
Time tolerance config now passes around timedelta objects instead of second values.
The ~pyhanko.sign.diff_analysis.commons.qualify function in the difference analysis has been split into ~pyhanko.sign.diff_analysis.commons.qualify and ~pyhanko.sign.diff_analysis.commons.qualify_transforming.
Certificate and key loading was moved to a new pyhanko.keys module, but pyhanko.sign.general still reexports the relevant functions for backwards compatibility. Concretely, the affected functions are
pyhanko.keys.load_cert_from_pemder,
pyhanko.keys.load_certs_from_pemder,
pyhanko.keys.load_certs_from_pemder_data,
pyhanko.keys.load_private_key_from_pemder,
pyhanko.keys.load_private_key_from_pemder_data.
Onboarded mypy and flag pyHanko as a typed library by adding py.typed.
Package metadata and tooling settings have now been centralised to pyproject.toml. Other configuration files like setup.py, requirements.txt and most tool-specific config have been eliminated.
The docstring-based documentation for pyhanko_certvalidator was added to the API reference.
Some non-autogenerated API reference documentation pages were consolidated to reduce the sprawl.
Heavily reworked the CI/CD pipeline. PyHanko releases are now published via GitHub Actions and signed with Sigstore. GPG signatures will continue to be provided for the time being.
Bump pyhanko-certvalidator to 0.22.0.
Relax the upper bound on uharfbuzz for better Python 3.11 support
The AdES LTA validator now tolerates documents that don't have a DSS (assuming that all the required information is otherwise present).
Ensure that the ~pyhanko.sign.validation.status.SignatureStatus.trusted attribute on ~pyhanko.sign.validation.status.SignatureStatus is not set if the validation path is not actually available.
Correct the typing on ~pyhanko.sign.validation.status.SignatureStatus.validation_path.
Fix several result presentation bugs in the AdES code.
Fix overeager sharing of ~pyhanko_certvalidator.ltv.poe.POEManager objects in AdES code.
Correct algo policy handling in AdES-with-time validation.
Ensure that container_ref is also populated on past versions of the trailer dictionary.
The CLI now features plugins! All current addsig subcommands have been reimplemented to use the plugin interface. Other plugins will be auto-detected through package entry points.
Refine algorithm policy handling; put in place a subclass of ~pyhanko_certvalidator.policy_decl.AlgorithmUsagePolicy specifically for CMS validation; see ~pyhanko.sign.validation.utils.CMSAlgorithmUsagePolicy.
Try to remember paths when validation fails.
Make certificates from local CMS context available during path building for past certificate validation (subject to PoE checks).
Move ~pyhanko.sign.validation.status.ModificationInfo.docmdp_ok up in the hierarchy to ~pyhanko.sign.validation.status.ModificationInfo.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.17.2 release are available here.
Release date: 2023-03-10
This is a follow-up on yesterday’s bugfix release, addressing a number of similar issues.
Address another potential infinite loop in the comment processing logic.
Fix some (rather esoteric) correctness issues w.r.t. PDF whitespace.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.17.1 release are available here.
Release date: 2023-03-09
This is a maintenance release without significant functionality changes. It contains a bugfix, addresses some documentation issues and applies the Black formatter to the codebase.
Address a potential infinite loop in the PDF parsing logic. See PR #237 .
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.17.0 release are available here.
Release date: 2023-01-31
This is a bit of an odd release. It comes with relatively few functional changes or enhancements to existing features, but it has nevertheless been in the works for quite a long time.
In early 2022, I decided that the time was right to equip pyHanko with its own AdES validation engine, implementing the machinery specified by ETSI EN 319 102-1. I knew ahead of time that this would not be an easy task:
PyHanko’s own validation code was put together in a fairly ad-hoc manner starting from the provisions in the CMS specification, so some refactoring would be necessary.
pyhanko-certvalidator also was never designed to be anything more than an RFC 5280 validation engine, and retrofitting the fine-tuning required by the AdES spec definitely wasn’t easy.
Initially, I estimated that this effort would take a few months tops. Yet here we are, approximately one year down the road: pyhanko.sign.validation.ades .
Truth be told, the implementation isn’t yet ready for prime time, but it is in a state where it’s at least useful for experimentation purposes, and can be iterated on. Also, given the volume of subtle changes and far-reaching refactoring in the internals of both the pyhanko and pyhanko-certvalidator packages, continually rebasing the feature/ades-validation feature branch turned into a chore quite quickly.
So, if you’re keen to start playing around with AdES validation: please do so, and let me know what you think. If standards-based validation is not something you care about, feel free to disregard everything I wrote above, it almost certainly won’t affect any of your code.
My plan is to incrementally build upon and polish the code in pyhanko.sign.validation.ades , and eventually deprecate the current ad-hoc LTV validation logic in pyhanko.sign.validation.ltv.async_validate_pdf_ltv_signature() . That’s still a ways off from now, though.
pyhanko-certvalidator updated to 0.20.0
There are various changes in the validation internals that are not backwards compatible, but all of those concern internal APIs.
There are some noteworthy changes to the pyhanko-certvalidator API. Those are documented in the change log . Most of these do not affect basic usage.
Experimental AdES validation engine pyhanko.sign.validation.ades .
In the status API, make a more meaningful distinction between valid and intact , and document that distinction.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.16.0 release are available here.
Release date: 2022-12-21
pyhanko-certvalidator updated to 0.19.8
This release includes breaking changes to the difference analysis engine. Unless you’re implementing your own difference analysis policies, this change should break your API usage.
Add support for Prop_Build metadata in signatures. See PR #192
Improvements to the difference analysis engine that allow more nuance to be expressed in the rule system.
Tolerate an indirect Extensions and MarkInfo dictionary in difference analysis. See PR #177 .
Gracefully handle unreadable/undecodable producer strings.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.15.1 release are available here.
Release date: 2022-10-27
This release adds Python 3.11 to the list of supported Python versions.
pyhanko-certvalidator updated to 0.19.6
certomancer updated to 0.9.1
Be more tolerant towards deviations from DER restrictions in signed attributes when validating signatures.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.15.0 release are available here.
Release date: 2022-10-11
Other than a few bug fixes, the highlight of this release is the addition of support for two very recently published PDF extension standards, ISO/TS 32001 and ISO/TS 32002.
Fix metadata handling in encrypted documents see issue #160 .
Make sure XMP stream dictionaries contain the required typing entries.
Respect visible_sig_settings on field autocreation.
Fix a division by zero corner case in the stamp layout code; see issue #170 .
Add support for the new PDF extensions defined by ISO/TS 32001 and ISO/TS 32002; see PR #169 .
SHA-3 support
EdDSA support for both the PKCS#11 signer and the in-memory signer
Auto-register developer extensions in the file
Make it easier to extract keys from bytes objects.
Add support for validating EdDSA signatures (as defined in ISO/TS 32002)
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.14.0 release are available here.
Release date: 2022-09-17
This release contains a mixture of minor and major changes. Of particular note is the addition of automated metadata management support, including XMP metadata. This change affects almost every PDF write operation in the background. While pyHanko has very good test coverage, some instability and regressions may ensue. Bug reports are obviously welcome.
The breaking changes in this release are all relatively minor. Chances are that your code isn’t affected at all, other than perhaps by the change to PreparedByteRangeDigest .
md_algorithm attribute removed from PreparedByteRangeDigest since it wasn’t necessary for further processing.
Low-level change in raw_get for PDF container object types ( ArrayObject and DictionaryObject ): the decrypt parameter is no longer a boolean, but a tri-state enum value of type EncryptedObjAccess .
Developer extension management API moved into pyhanko.pdf_utils.extensions .
get_courier() convenience function moved into pyhanko.pdf_utils.font.basic and now takes a mandatory writer argument.
The token_label attribute was removed from PKCS11SignatureConfig , but will still be parsed (with a deprecation warning).
The prompt_pin attribute in PKCS11SignatureConfig was changed from a bool to an enum. See PKCS11PinEntryMode .
pytest-aiohttp updated to 1.0.4
certomancer updated to 0.9.0
certomancer-csc-dummy updated to 0.2.1
Relax bounds on uharfbuzz to allow everything up to the current version (i.e. 0.30.0 ) as well.
New optional dependency group xmp , which for now only contains defusedxml
Allow certificates with no CN in the certificate subject.
The extension dictionary handling logic can now deal with encrypted documents without actually decrypting the document contents.
Fix processing error when passing empty strings to uharfbuzz ; see issue #132 .
Use proper PDF text string serialisation routine in simple font handler, to ensure everything is escaped correctly.
Ensure that output_version is set to at least the input version in incrementally updated files.
Drop the requirement for signing_cert to be set from the start of the signing process in an interrupted signing workflow. This has come up on several occasions in the past, since it’s necessary in remote signing scenarios where the certificate is generated or provided on-demand when submitting the document digest to the signing service. See pull #141 for details.
Add convenience API to set the /TU entry on a signature field; see readable_field_name .
Allow greater control over the initialisation of document timestamp fields.
New class hierarchy for (un)signed attribute provisioning; see SignedAttributeProviderSpec and UnsignedAttributeProviderSpec .
Allow greater control over annotation flags for visible signatures. This is implemented using VisibleSigSettings . See discussion #150 .
Factor out and improve PKCS#11 token finding; see TokenCriteria and issue #149 .
Factor out and improve PKCS#11 mechanism selection, allowing more raw modes.
Change pin entry settings for PKCS#11 to be more granular, in order to also allow PROTECTED_AUTH ; see issue #133 .
Allow the PKCS#11 PIN to be sourced from an environment variable when pyHanko is invoked through the CLI and no PIN is provided in the configuration. PyHanko will now first check the PYHANKO_PKCS11_PIN variable before prompting for a PIN. This also works when prompting for PIN entry is disabled altogether.
Note
The PKCS#11 code is now also tested in CI, using SoftHSMv2 .
Allow validation time overrides in the CLI. Passing in the special value claimed tells pyHanko to take the stated signing time in the file at face value. See issue #130 .
Also return permissions on owner access to allow for easier inspection.
Better version enforcement for security handlers.
Allow metrics to be specified for simple fonts.
Provide metrics for default Courier font.
Experimental option that allows graphics to be embedded in the central area of the QR code; see qr_inner_content .
Basic XMP metadata support with optional xmp dependency group.
Automated metadata management (document info dictionary, XMP metadata).
Refactor some low-level digesting and CMS validation code.
Make the CLI print a warning when the key passphrase is left empty.
Tweak configuration management utilities to better cope with fallback logic for deprecated configuration parameters.
Move all cross-reference writing logic into pyhanko.pdf_utils.xref .
Improve error classes and error reporting in the CLI so that errors in non-verbose mode still provide a little more info.
Release date: 2022-09-17
This release contains a mixture of minor and major changes. Of particular note is the addition of automated metadata management support, including XMP metadata. This change affects almost every PDF write operation in the background. While pyHanko has very good test coverage, some instability and regressions may ensue. Bug reports are obviously welcome.
The breaking changes in this release are all relatively minor. Chances are that your code isn't affected at all, other than perhaps by the change to ~pyhanko.sign.signers.pdf_byterange.PreparedByteRangeDigest.
md_algorithm attribute removed from ~pyhanko.sign.signers.pdf_byterange.PreparedByteRangeDigest since it wasn't necessary for further processing.
Low-level change in raw_get for PDF container object types (~pyhanko.pdf_utils.generic.ArrayObject and ~pyhanko.pdf_utils.generic.DictionaryObject): the decrypt parameter is no longer a boolean, but a tri-state enum value of type ~pyhanko.pdf_utils.generic.EncryptedObjAccess.
Developer extension management API moved into pyhanko.pdf_utils.extensions.
~pyhanko.pdf_utils.font.basic.get_courier convenience function moved into pyhanko.pdf_utils.font.basic and now takes a mandatory writer argument.
The token_label attribute was removed from ~pyhanko.cli.config.PKCS11SignatureConfig, but will still be parsed (with a deprecation warning).
The ~pyhanko.cli.config.PKCS11SignatureConfig.prompt_pin attribute in ~pyhanko.cli.config.PKCS11SignatureConfig was changed from a bool to an enum. See ~pyhanko.cli.config.PKCS11PinEntryMode.
pytest-aiohttp updated to 1.0.4
certomancer updated to 0.9.0
certomancer-csc-dummy updated to 0.2.1
Relax bounds on uharfbuzz to allow everything up to the current version (i.e. 0.30.0) as well.
New optional dependency group xmp, which for now only contains defusedxml
Allow certificates with no CN in the certificate subject.
The extension dictionary handling logic can now deal with encrypted documents without actually decrypting the document contents.
Fix processing error when passing empty strings to uharfbuzz; see issue #132.
Use proper PDF text string serialisation routine in simple font handler, to ensure everything is escaped correctly.
Ensure that output_version is set to at least the input version in incrementally updated files.
Drop the requirement for ~pyhanko.sign.signers.pdf_cms.Signer.signing_cert to be set from the start of the signing process in an interrupted signing workflow. This has come up on several occasions in the past, since it's necessary in remote signing scenarios where the certificate is generated or provided on-demand when submitting the document digest to the signing service. See pull #141 for details.
Add convenience API to set the /TU entry on a signature field; see ~pyhanko.sign.fields.SigFieldSpec.readable_field_name.
Allow greater control over the initialisation of document timestamp fields.
New class hierarchy for (un)signed attribute provisioning; see ~pyhanko.sign.attributes.SignedAttributeProviderSpec and ~pyhanko.sign.attributes.UnsignedAttributeProviderSpec.
Allow greater control over annotation flags for visible signatures. This is implemented using ~pyhanko.sign.fields.VisibleSigSettings. See discussion #150.
Factor out and improve PKCS#11 token finding; see ~pyhanko.cli.config.TokenCriteria and issue #149.
Factor out and improve PKCS#11 mechanism selection, allowing more raw modes.
Change pin entry settings for PKCS#11 to be more granular, in order to also allow PROTECTED_AUTH; see issue #133.
Allow the PKCS#11 PIN to be sourced from an environment variable when pyHanko is invoked through the CLI and no PIN is provided in the configuration. PyHanko will now first check the PYHANKO_PKCS11_PIN variable before prompting for a PIN. This also works when prompting for PIN entry is disabled altogether.
Note
The PKCS#11 code is now also tested in CI, using SoftHSMv2.
Allow validation time overrides in the CLI. Passing in the special value claimed tells pyHanko to take the stated signing time in the file at face value. See issue #130.
Also return permissions on owner access to allow for easier inspection.
Better version enforcement for security handlers.
Allow metrics to be specified for simple fonts.
Provide metrics for default Courier font.
Experimental option that allows graphics to be embedded in the central area of the QR code; see ~pyhanko.stamp.QRStampStyle.qr_inner_content.
Basic XMP metadata support with optional xmp dependency group.
Automated metadata management (document info dictionary, XMP metadata).
Refactor some low-level digesting and CMS validation code.
Make the CLI print a warning when the key passphrase is left empty.
Tweak configuration management utilities to better cope with fallback logic for deprecated configuration parameters.
Move all cross-reference writing logic into pyhanko.pdf_utils.xref.
Improve error classes and error reporting in the CLI so that errors in non-verbose mode still provide a little more info.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.13.2 release are available here.
Release date: 2022-07-02
This is a patch release to address some dependency issues and bugs.
python-barcode updated and pinned to 0.14.0 .
Fix lack of newline after XRef stream header.
Do not write DigestMethod in signature reference dictionaries (deprecated/nonfunctional entry).
Make pyhanko.pdf_utils.writer.copy_into_new_writer() more flexible by allowing caller-specified keyword arguments for the writer object.
Refine settings for invisible signature fields (see pyhanko.sign.fields.InvisSigSettings ).
Correctly read objects from object streams in encrypted documents.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.13.1 release are available here.
Release date: 2022-05-01
This is a patch release to update fontTools and uharfbuzz to address a conflict between the latest fontTools and older uharfbuzz versions.
fontTools updated to 4.33.3
uharfbuzz updated to 0.25.0
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.13.0 release are available here.
Release date: 2022-04-25
Like the previous two releases, this is largely a maintenance release.
asn1crypto updated to 1.5.1
pyhanko-certvalidator updated to 0.19.5
certomancer updated to 0.8.2
Depend on certomancer-csc-dummy for tests; get rid of python-pae test dependency.
Various parsing robustness improvements.
Be consistent with security handler version bounds.
Improve coverage of encryption code.
Ensure owner password gets prioritised in the legacy security handler.
Replaced some ValueError usages with PdfError
Improvements to error handling in strict mode.
Make CLI stack traces less noisy by default.
Refactor internal crypt module into package.
Add support for serialising credentials.
Cleaner credential inheritance for incremental writers.
Allow post-signing actions on encrypted files with serialised credentials.
Improve --use-pades-lta ergonomics in CLI.
Add --no-pass parameter to pemder CLI.
Preparatory scaffolding for AdES status reporting.
Provide some tolerance against malformed ACs.
Increase robustness against invalid DNs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.12.1 release are available here.
Release date: 2022-02-26
uharfbuzz updated to 0.19.0
pyhanko-certvalidator updated to 0.19.4
certomancer updated to 0.8.1
Fix typing issue in DSS reading logic (see issue #81 )
Release date: 2022-02-26
uharfbuzz updated to 0.19.0
pyhanko-certvalidator updated to 0.19.4
certomancer updated to 0.8.1
Fix typing issue in DSS reading logic (see issue #81)
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
The release notes for the 0.12.0 release are available here.
Release date: 2022-01-26
This is largely a maintenance release, and contains no new high-level features or public API changes. As such, upgrading is strongly recommended.
The most significant change is the (rather minimalistic) support for hybrid reference files. Since working with hybrid reference files means dealing with potential ambiguity (which is dangerous when dealing with signatures), creation and validation of signatures in hybrid reference documents is only enabled in nonstrict mode. Hybrid reference files are relatively rare these days, but the internals need to be able to cope with them either way, in order to be able to update such files safely.
Significant refactor of cross-reference parsing internals. This doesn’t affect any public API entrypoints, but read the reference documentation for pyhanko.pdf_utils.xref if you happen to have code that directly relies on that internal logic.
Minimal support for hybrid reference files.
Add strict flag to IncrementalPdfFileWriter .
Expose --no-strict-syntax CLI flag in the addsig subcommand.
Ensure that signature appearance bounding boxes are rounded to a reasonable precision. Failure to do so caused issues with some viewers.
To be consistent with the purpose of the strictness flag, non-essential xref consistency checking is now only enabled when running in strict mode (which is the default).
The hybrid reference support indirectly fixes some potential silent file corruption issues that could arise when working on particularly ill-behaved hybrid reference files.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Warning: Some validation-related classes have been moved in this release. Please review the release notes before updating.
The release notes for the 0.11.0 release are available here.
Release date: 2021-12-23
Update pyhanko-certvalidator to 0.19.2
Bump fontTools to 4.28.2
Update certomancer test dependency to 0.7.1
Due to import order issues resulting from refactoring of the validation code, some classes and class hierarchies in the higher-level API had to be moved. The affected classes are listed below, with links to their respective new locations in the API reference.
KeyUsageConstraints
SignatureValidationError
WeakHashAlgorithmError
SigSeedValueValidationError
SignatureStatus
StandardCMSSignatureStatus
PdfSignatureStatus
TimestampSignatureStatus
DocumentTimestampStatus
The low-level function validate_sig_integrity() was also moved.
Support embedding attribute certificates into CMS signatures, either in the certificates field or using the CAdES signer-attrs-v2 attribute.
More explicit errors on unfulfilled text parameters
Better use of asyncio when collecting validation information for timestamps
Internally disambiguate PAdES and CAdES for the purpose of attribute handling.
Refactor diff_analysis module into sub-package
Refactor validation module into sub-package (together with portions of pyhanko.sign.general ); see Breaking changes .
Make extracted certificate information more easily accessible.
Integrated attribute certificate validation (requires a separate validation context with trust roots for attribute authorities)
Report on signer attributes as supplied by the CAdES signer-attrs-v2 attribute.
Various parsing and error handling improvements to xref processing, object streams, and object header handling.
Use NotImplementedError for unimplemented stream filters instead of less-appropriate exceptions
Always drop GPOS/GDEF/GSUB when subsetting OpenType and TrueType fonts
Initial support for string-keyed CFF fonts as CIDFonts (subsetting is still inefficient)
copy_into_new_writer() is now smarter about how it deals with the /Producer line
Fix a typo in the ASN.1 definition of signature-policy-store
Various, largely aesthetic, cleanup & docstring fixes in internal APIs
Fix a critical bug in content timestamp generation causing the wrong message imprint to be sent to the timestamping service. The bug only affected the signed content-time-stamp attribute from CAdES, not the (much more widely used) signature-time-stamp attribute. The former timestamps the content (and is part of the signed data), while the latter timestamps the signature (and is therefore not part of the signed data).
Fix a bug causing an empty unsigned attribute sequence to be written if there were no unsigned attributes. This is not allowed (although many validators accept it), and was a regression introduced in 0.9.0 .
Ensure non-PDF CAdES signatures always have signingTime set.
Fix and improve timestamp summary reporting
Corrected TrueType subtype handling
Properly set ts_validation_paths
Gracefully deal with unsupported certificate types in CMS
Ensure attribute inspection internals can deal with SignerInfo without signedAttrs .
Release date: 2021-12-23
Update pyhanko-certvalidator to 0.19.2
Bump fontTools to 4.28.2
Update certomancer test dependency to 0.7.1
Due to import order issues resulting from refactoring of the validation code, some classes and class hierarchies in the higher-level API had to be moved. The affected classes are listed below, with links to their respective new locations in the API reference.
~pyhanko.sign.validation.settings.KeyUsageConstraints
~pyhanko.sign.validation.errors.SignatureValidationError
~pyhanko.sign.validation.errors.WeakHashAlgorithmError
~pyhanko.sign.validation.errors.SigSeedValueValidationError
~pyhanko.sign.validation.status.SignatureStatus
~pyhanko.sign.validation.status.StandardCMSSignatureStatus
~pyhanko.sign.validation.status.PdfSignatureStatus
~pyhanko.sign.validation.status.TimestampSignatureStatus
~pyhanko.sign.validation.status.DocumentTimestampStatus
The low-level function ~pyhanko.sign.validation.generic_cms.validate_sig_integrity was also moved.
Support embedding attribute certificates into CMS signatures, either in the certificates field or using the CAdES signer-attrs-v2 attribute.
More explicit errors on unfulfilled text parameters
Better use of asyncio when collecting validation information for timestamps
Internally disambiguate PAdES and CAdES for the purpose of attribute handling.
Refactor diff_analysis module into sub-package
Refactor validation module into sub-package (together with portions of pyhanko.sign.general); see release-0.11.0-breaking.
Make extracted certificate information more easily accessible.
Integrated attribute certificate validation (requires a separate validation context with trust roots for attribute authorities)
Report on signer attributes as supplied by the CAdES signer-attrs-v2 attribute.
Various parsing and error handling improvements to xref processing, object streams, and object header handling.
Use NotImplementedError for unimplemented stream filters instead of less-appropriate exceptions
Always drop GPOS/GDEF/GSUB when subsetting OpenType and TrueType fonts
Initial support for string-keyed CFF fonts as CIDFonts (subsetting is still inefficient)
~pyhanko.pdf_utils.writer.copy_into_new_writer is now smarter about how it deals with the /Producer line
Fix a typo in the ASN.1 definition of signature-policy-store
Various, largely aesthetic, cleanup & docstring fixes in internal APIs
Fix a critical bug in content timestamp generation causing the wrong message imprint to be sent to the timestamping service. The bug only affected the signed content-time-stamp attribute from CAdES, not the (much more widely used) signature-time-stamp attribute. The former timestamps the content (and is part of the signed data), while the latter timestamps the signature (and is therefore not part of the signed data).
Fix a bug causing an empty unsigned attribute sequence to be written if there were no unsigned attributes. This is not allowed (although many validators accept it), and was a regression introduced in 0.9.0.
Ensure non-PDF CAdES signatures always have signingTime set.
Fix and improve timestamp summary reporting
Corrected TrueType subtype handling
Properly set ~pyhanko.sign.signers.pdf_signer.PreSignValidationStatus.ts_validation_paths
Gracefully deal with unsupported certificate types in CMS
Ensure attribute inspection internals can deal with SignerInfo without signedAttrs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Note: I recently rotated my PGP key, as recorded on my website, where you can also download a copy of the public key file of the new Ed25519 key, signed with the old one. The artifacts attached to this GitHub release are signed with the new key.
The release notes for the 0.10.0 release are available here.
Release date: 2021-11-28
Update pyhanko-certvalidator to 0.18.0
Update aiohttp to 3.8.0 (optional dependency)
Introduce python-pae==0.1.0 (tests)
There’s a new Signer implementation that allows pyHanko to be used with remote signing services that implement the Cloud Signature Consortium API. Since auth handling differs from vendor to vendor, using this feature requires still the caller to supply an authentication handler implementation; see pyhanko.sign.signers.csc_signer for more information. This feature is currently incubating.
Add CLI option to skip diff analysis.
Add CLI flag to disable strict syntax checks.
Use chunked digests while validating.
Improved difference analysis logging.
Better handling of nonexistent objects: clearer errors in strict mode, better fallback behaviour in nonstrict mode. This applies to both regular object dereferencing and xref history analysis.
Added many new tests for various edge cases, mainly in validation code.
Added Python :: 3 and Python :: 3.10 classifiers to distribution.
Fix bug in output handler in timestamp updater that caused empty output in some configurations.
Fix a config parsing error when no stamp styles are defined in the configuration file.
Warning: This release brings improved asyncio support, but contains major breaking changes in the lower-level API. Review the release notes carefully…
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Warning: This release brings improved asyncio support, but contains major breaking changes in the lower-level API. Review the release notes carefully before updating if you use these low-level functions!
The release notes for the 0.9.0 release are available here.
Release date: 2021-10-31
Update pyhanko-certvalidator to 0.17.3
Update fontTools to 4.27.1
Update certomancer to 0.6.0 (tests)
Introduce pytest-aiohttp~=0.3.0 and aiohttp>=3.7.4 (tests)
This is a pretty big release, with a number of far-reaching changes in the lower levels of the API that may cause breakage. Much of pyHanko’s internal logic has been refactored to prefer asynchronous I/O wherever possible ( pyhanko-certvalidator was also refactored accordingly). Some compromises were made to allow non-async-aware code to continue working as-is.
If you’d like a quick overview of how you can take advantage of the new asynchronous library functions, take a look at this section in the signing docs .
Here’s an overview of low-level functionality that changed:
CMS signing logic was refactored and made asynchronous (only relevant if you implemented your own custom signers)
Time stamp client API was refactored and made asynchronous (only relevant if you implemented your own time stamping clients)
The interrupted signing workflow now involves more asyncio as well.
perform_presign_validation() was made asynchronous.
prepare_tbs_document() : the bytes_reserved parameter is mandatory now.
post_signature_processing() was made asynchronous.
collect_validation_info() was made asynchronous
Other functions have been deprecated in favour of asynchronous equivalents; such deprecations are documented in the API reference . The section on extending Signer has also been updated .
Warning
Even though we have pretty good test coverage, due to the volume of changes, some instability may ensue. Please do not hesitate to report bugs on the issue tracker !
Async-first signing API
Relax token-label requirements in PKCS#11 config, allowing slot-no as an alternative
Allow selecting keys and certificates by ID in the PKCS#11 signer
Allow the signer’s certificate to be sourced from a file in the PKCS#11 signer
Allow BeID module path to be specified in config
Tweak cert querying logic in PKCS#11 signer
Add support for raw ECDSA to the PKCS#11 signer
Basic DSA support (for completeness w.r.t. ISO 32000)
Choose a default message digest more cleverly, based on the signing algorithm and key size
Fail loudly when trying to add a certifying signature to an already-signed document using the high-level signing API
Provide a flag to skip embedding root certificates
Async-first validation API
Use non-zero exit code on failed CLI validation
Minor reorganisation of config.py functions
Move PKCS#11 pin prompt logic to cli.py
Improve font embedding efficiency (better stream management)
Ensure idempotence of object stream flushing
Improve PKCS#11 signer logging
Make stream_xrefs=False by default in copy_into_new_writer()
Removed a piece of fallback logic for md_algorithm that relied on obsolete parts of the standard
Fixed a number of issues related to unexpected cycles in PDF structures
Treat ASCII form feed ( \f ) as PDF whitespace
Fix a corner case with null incremental updates
Fix some font compatibility issues (relax assumptions about the presence of certain tables/entries)
Be more tolerant when parsing name objects
Correct some issues related to DSS update validation
Correct pdf_date() output for negative UTC offsets
Warning: This release contains a very minor API-breaking change in the configuration API. Since the configuration API is mostly intended as a tool for…
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Warning: This release contains a very minor API-breaking change in the configuration API. Since the configuration API is mostly intended as a tool for pyHanko's CLI functionality, most users should be unaffected.
The release notes for the 0.8.0 release are available here.
Release date: 2021-08-23
Update pyhanko-certvalidator to 0.16.0 .
Some fields and method names in the config API misspelled pkcs11` as ``pcks11 . This has been corrected in this release. This is unlikely to cause issues for library users (since the config API is primarily used by the CLI code), but it’s a breaking change all the same. If you do have code that relies on the config API, simply substituting s/pcks/pkcs/g should fix things.
Make certificate fetching in the PKCS#11 signer more flexible.
Allow passing in the signer’s certificate from outside the token.
Improve certificate registry initialisation.
Give more control over updating the DSS in complex signature workflows. By default, pyHanko now tries to update the DSS in the revision that adds a document timestamp, after the signature (if applicable). In the absence of a timestamp, the old behaviour persists.
Added a flag to (attempt to) produce CMS signature containers without any padding.
Use signing-certificate-v2 instead of signing-certificate when producing signatures.
Default to empty appearance streams for empty signature fields.
Much like the pkcs11-setups config entry, there are now pemder-setups and pkcs12-setups at the top level of pyHanko’s config file. You can use those to store arguments for the pemder and pkcs12 subcommands of pyHanko’s addsig command, together with passphrases for non-interactive use. See Named setups for on-disk key material .
Enforce the end-entity cert constraint imposed by the signing-certificate or signing-certificate-v2 attribute (if present).
Improve issuer-serial matching logic.
Improve CMS attribute lookup routines.
Add a flag to suppress creating “legacy compatibility” entries in the encryption dictionary if they aren’t actually required or meaningful (for now, this only applies to /Length ).
Lazily load the version entry in the catalog.
Minor internal I/O handling improvements.
Allow constructing an IncrementalPdfFileWriter from a PdfFileReader object.
Expose common API to modify (most) trailer entries.
Automatically recurse into all configurable fields when processing configuration data.
Replace some certificate storage/indexing classes by references to their corresponding classes in pyhanko-certvalidator .
Add /NeedAppearances in the AcroForm dictionary to the whitelist for incremental update analysis.
Fixed several bugs related to difference analysis on encrypted files.
Improve behaviour of dev extensions in difference analysis.
Fix encoding issues with SignedDigestAlgorithm , in particular ensuring that the signature mechanism encodes the relevant digest when using ECDSA.
Process passfile contents more robustly in the CLI.
Correct timestamp revinfo fetching (by ensuring that a dummy response is present)
Warning: This release contains a number of API-breaking changes. While the high-level APIs shouldn't be affected, please review the release notes care…
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Warning: This release contains a number of API-breaking changes. While the high-level APIs shouldn't be affected, please review the release notes carefully before updating.
Note: From this release onwards, the content of the release history page in pyHanko's documentation will no longer be duplicated here for every release. Detailed release notes will continue to be published there.
The release notes for the 0.7.0 release are available here.
Release date: 2021-07-25
Warning
If you used OTF/TTF fonts with pyHanko prior to the 0.7.0 release, you’ll need HarfBuzz going forward. Install pyHanko with the [opentype] optional dependency group to grab everything you need.
Update pyhanko-certvalidator to 0.15.3
TrueType/OpenType support moved to new optional dependency group labelled [opentype] .
Dependency on fontTools moved from core dependencies to [opentype] group.
We now use HarfBuzz ( uharfbuzz==0.16.1 ) for text shaping with OTF/TTF fonts.
Warning
If you use any of pyHanko’s lower-level APIs, review this section carefully before updating.
This release includes a refactor of the pyhanko.sign.signers module into a package with several submodules. The original API exposed by this module is reexported in full at the package level, so existing code using pyHanko’s publicly documented signing APIs should continue to work without modification .
There is one notable exception: as part of this refactor, the low-level PdfCMSEmbedder protocol was tweaked slightly, to support the new interrupted signing workflow (see below). The required changes to existing code should be minimal; have a look at the relevant section in the library documentation for a concrete description of the changes, and an updated usage example.
In addition, if you extended the PdfSigner class, then you’ll have to adapt to the new internal signing workflow as well. This may be tricky due to the fact that the separation of concerns between different steps in the signing process is now enforced more strictly. I’m not aware of use cases requiring PdfSigner to be extended, but if you’re having trouble migrating your custom subclass to the new API structure, feel free to open an issue . Merely having subclassed Signer shouldn’t require you to change anything.
The low-level font loading API has been refactored to make font resource handling less painful, to provide smoother HarfBuzz integration and to expose more OpenType tweaks in the API.
To this end, the old pyhanko.pdf_utils.font module was turned into a package containing three modules: api , basic and opentype . The api module contains the definitions for the general FontEngine and FontEngineFactory classes, together with some other general plumbing logic. The basic module provides a minimalist implementation with a (non-embedded) monospaced font. If you need TrueType/OpenType support, you’ll need the opentype module together with the optional dependencies in the [opentype] dependency group (currently fontTools and uharfbuzz , see above). Take a look at the section for pyhanko.pdf_utils.font in the API reference documentation for further details.
For the time being, there are no plans to support embedding Type1 fonts, or to offer support for Type3 fonts at all.
The content_stream parameter was removed from import_page_as_xobject() . Content streams are now merged automatically, since treating a page content stream array non-atomically is a bad idea.
PdfSigner is no longer a subclass of PdfTimeStamper .
Interrupted signing workflow: segmented signing workflow that can be interrupted partway through and resumed later (possibly in a different process or on a different machine). Useful for dealing with signing processes that rely on user interaction and/or remote signing services.
Generic data signing support: construct CMS signedData objects for arbitrary data (not necessarily for use in PDF signature fields).
Experimental API for signing individual embedded files (nonstandard).
PKCS#11 settings can now be set in the configuration file.
Add support for validating CMS signedData structures against arbitrary payloads (see also: Generic data signing )
Streamline CMS timestamp validation.
Support reporting on (CAdES) content timestamps in addition to signature timestamps.
Allow signer certificates to be identified by the subjectKeyIdentifier extension.
Support granular crypt filters for embedded files
Add convenient API to encrypt and wrap a PDF document as a binary blob. The resulting file will open as usual in a viewer that supports PDF collections; a fallback page with alternative instructions is shown otherwise.
Complete overhaul of appearance generation & layout system. Most of these changes are internal, except for some font loading mechanics (see above). All use of OpenType / TrueType fonts now requires the [opentype] optional dependency group. New features:
Use HarfBuzz for shaping (incl. complex scripts)
Support TrueType fonts and OpenType fonts without a CFF table.
Support vertical writing (among other OpenType features).
Use ActualText marked content in addition to ToUnicode.
Introduce simple box layout & alignment rules, and apply them uniformly across all layout decisions where possible. See pyhanko.stamp and pyhanko.pdf_utils.layout for API documentation.
Refactored stamp style dataclass hierarchy. This should not affect existing code.
Allow externally generated PDF content to be used as a stamp appearance.
Utility API for embedding files into PDF documents.
Added support for PDF developer extension declarations.
Declare ESIC extension when producing a PAdES signature on a PDF 1.x file.
Fix handling of orphaned objects in diff analysis.
Tighten up tolerances for (visible) signature field creation.
Fix typo in BaseFieldModificationRule
Deal with some VRI-related corner cases in the DSS diffing logic.
Improve identity crypt filter behaviour when applied to text strings.
Correct handling of non-default public-key crypt filters.
Promote stream manipulation methods to base writer.
Correct some edge cases w.r.t. PDF content import
Use floats for MediaBox.
Handle escapes in PDF name objects.
Correct ToUnicode CMap formatting.
Do not close over GSUB when computing font subsets.
Fix output_version handling oversight.
Misc. export list & type annotation corrections.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
pyhanko-certvalidator to 0.15.2certomancer and pyhanko-certvalidator by soft minor version constraint (~=)freezegunRelease date: 2021-05-22
Update pyhanko-certvalidator to 0.15.2
Replace constraint on certomancer and pyhanko-certvalidator by soft minor version constraint ( ~= )
Set version bound for freezegun
Add /Q and /DA keys to the whitelist for incremental update analysis on form fields.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Warning: pyHanko's 0.6.0 release includes quite a few changes to dependencies, some of which may
break compatibility with existing code. Review this section carefully before updating.
The pyhanko-certvalidator dependency was updated to 0.15.1. This update adds support for name constraints, RSASSA-PSS and EdDSA for the purposes of X.509 path validation, OCSP checking and CRL validation.
Since pyhanko-certvalidator has considerably diverged from "mainline" certvalidator, the Python package containing its modules was also renamed from certvalidator to pyhanko_certvalidator, to avoid potential namespace conflicts down the line. You should update your code to reflect this change. Concretely, from certvalidator import ValidationContext turns into from pyhanko_certvalidator import ValidationContext in the new release.
There were several changes to dependencies with native binary components:
The Pillow dependency has been relaxed to >=7.2.0, and is now optional. The same goes for python-barcode. Image & 1D barcode support now needs to be installed explicitly using the [image-support] installation parameter.
PKCS#11 support has also been made optional, and can be added using the [pkcs11] installation parameter.
The test suite now makes use of Certomancer. This also removed the dependency on ocspbuilder.
/AP when creating an empty visible signature field (necessary in PDF 2.0)Timestamp and DSS handling tweaks:
validation_context parameter is now optional.Enforce certvalidator's weak_hash_algos when validating PDF signatures as well. Previously, this setting only applied to certificate validation. By default, MD5 and SHA-1 are considered weak (for digital signing purposes).
Expose DocTimeStamp/Sig distinction in a more user-friendly manner.
sig_object_type property on EmbeddedPdfSignature now returns the signature's type as a PDF name object.PdfFileReader now has two extra convenience properties named embedded_regular_signatures and embedded_timestamp_signatures, that return a list of all regular signatures and document timestamps, respectively.1.0.0).--soft-revocation-check.validate_sig_integrity.pyca/cryptography rather than hashlib.NUL bytes in array literals.The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Release date: 2021-03-24
Fixed a packaging blunder that caused an import error on fresh installs.
Release date: 2021-03-24
Fixed a packaging blunder that caused an import error on fresh installs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to [PyPI](https://pypi.org/project/pyHanko/0.5.0/). Documentation is available on [ReadTheDocs](https://pyhanko.readthedocs.io/en/0.5.0/).
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
## Change log
### Dependency changes
Update pyhanko-certvalidator dependency to 0.13.0. Dependency on cryptography is now mandatory, and oscrypto has been marked optional. This is because we now use the cryptography library for all signing and encryption operations, but some cryptographic algorithms listed in the PDF standard are not available in cryptography, so we rely on oscrypto for those. This is only relevant for the decryption of files encrypted with a public-key security handler that uses DES, triple DES or RC2 to encrypt the key seed.
In the public API, we exclusively work with asn1crypto representations of ASN.1 objects, to remain as backend-independent as possible.
Note: While oscrypto is listed as optional in pyHanko's dependency list, it is still required in practice, since pyhanko-certvalidator depends on it.
### New features and enhancements
#### Encryption
Enforce keyEncipherment key extension by default when using public-key encryption
Show a warning when signing a document using public-key encryption through the CLI. We currently don't support using separate encryption credentials in the CLI, and using the same key pair for decryption and signing is bad practice.
Several minor CLI updates.
#### Signing
Allow customisation of key usage requirements in signer & validator, also in the CLI.
Actively preserve document timestamp chain in new PAdES-LTA signatures.
Support setups where fields and annotations are separate (i.e. unmerged).
Set the lock bit in the annotation flags by default.
Tolerate signing fields that don't have any annotation associated with them.
Broader support for PAdES / CAdES signed attributes.
#### Validation
Support validating PKCS #7 signatures that don't use signedAttrs. Nowadays, those are rare in the wild, but there's at least one common commercial PDF library that outputs such signatures by default (vendor name redacted to protect the guilty).
- Timestamp-related fixes:
Improve signature vs. document timestamp handling in the validation CLI.
Improve & test handling of malformed signature dictionaries in PDF files.
Align document timestamp updating logic with validation logic.
Correct key usage check for time stamp validation.
Allow customisation of key usage requirements in signer & validator, also in the CLI.
Allow LTA update function to be used to start the timestamp chain as well as continue it.
Tolerate indirect references in signature reference dictionaries.
Improve some potential ambiguities in the PAdES-LT and PAdES-LTA validation logic.
- Revocation info handling changes:
Support "retroactive" mode for revocation info (i.e. treat revocation info as valid in the past).
Added functionality to append current revocation information to existing signatures.
Related CLI updates.
#### Miscellaneous
Some key material loading functions were cleaned up a little to make them easier to use.
I/O tweaks: use chunked writes with a fixed buffer when copying data for an incremental update
Warn when revocation info is embedded with an offline validation context.
Improve SV validation reporting.
#### Bugs fixed
Fix issue with /Certs not being properly dereferenced in the DSS (#4).
Fix loss of precision on ~pyhanko.pdf_utils.generic.FloatObject serialisation (#5).
Add missing dunders to ~pyhanko.pdf_utils.generic.BooleanObject.
Do not use .dump() with force=True in validation.
Corrected digest algorithm selection in timestamp validation.
Correct handling of writes with empty user password.
Do not automatically add xref streams to the object cache. This avoids a class of bugs with some kinds of updates to files with broken xref streams.
Due to a typo, the /Annots array of a page would not get updated correctly if it was an indirect object. This has been corrected.
The release artifacts have been published to PyPI.
Documentation is available on ReadTheDocs.
The release notes for the 0.5.0 release are available on the Release History page
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
PdfSignedData for non-signing usesunsigned_attrs in signer, added a digest_algorithm parameter to signed_attrs.BasePdfFileWriter (in particular, this allows creating signatures in the initial revision of a PDF file)CMSAlgorithmProtection attribute when possible
externally_invalid API parameter to encap_data_invalidCMSAlgorithmProtection when present.copy_into_new_writer.__iadd__ implementation from VRI class.container_ref handling.SignatureFormField initialisation (internal API).signed_revision on embedded signatures more robust./All-type field locks.modification_level handling in validation status reports.The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
RC4 class (not that it matters all to much, RC4 isn't secure anyhow); all cryptographic operations in crypt.py are now delegated to oscrypto.cryptography dependency, pyHanko can now create RSASSA-PSS signatures.PdfCMSEmbedder API to cater to remote signing needs.version.py.PdfFileWriter is now optional.cryptography dependency, pyHanko can now validate RSASSA-PSS signatures.diff_analysis module itself, and do not impact the general validation API whatsoever./DR and /Version updates in diff analysistrailer.flatten()The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
/Metadata updates more correctly, and fixes a number of other minor stability problems./V, /MDP, /LockDocument, /KeyUsage and (passive) support for /AppearanceFilter and /LegalAttestation.null objects instead of (Python) None.root_ref now consistently returns a Reference object@freeze_time in tests that caused some failures due to certificate expiry issues.HistoricalResolver that sometimes leaked state from later revisions into older ones.This is the initial alpha release for pyHanko; future releases will include a change log.
This is the initial alpha release for pyHanko; future releases will include a change log.
The release has been uploaded to PyPI. Documentation is available on ReadTheDocs.
Note: The public API is not completely stable yet, so future releases may still include API changes. This is particularly likely for the validation code and the pdf_utils package; please refer to the documentation for further details.
Your coding agent can read these notes before it upgrades. Set up the MCP server →