pyhanko.sign.validation module

class pyhanko.sign.validation.SignatureCoverageLevel(value)

Bases: pyhanko.pdf_utils.misc.OrderedEnum

Indicate the extent to which a PDF signature (cryptographically) covers a document. Note that this does not pass judgment on whether uncovered updates are legitimate or not, but as a general rule, a legitimate signature will satisfy at least ENTIRE_REVISION.

UNCLEAR = 0

The signature’s coverage is unclear and/or disconnected. In standard PDF signatures, this is usually a bad sign.

CONTIGUOUS_BLOCK_FROM_START = 1

The signature covers a contiguous block in the PDF file stretching from the first byte of the file to the last byte in the indicated /ByteRange. In other words, the only interruption in the byte range is fully occupied by the signature data itself.

ENTIRE_REVISION = 2

The signature covers the entire revision in which it occurs, but incremental updates may have been added later. This is not necessarily evidence of tampering. In particular, it is expected when a file contains multiple signatures. Nonetheless, caution is required.

ENTIRE_FILE = 3

The entire file is covered by the signature.

class pyhanko.sign.validation.PdfSignatureStatus(intact: bool, valid: bool, trusted: bool, revoked: bool, signing_cert: asn1crypto.x509.Certificate, pkcs7_signature_mechanism: str, md_algorithm: str, validation_path: certvalidator.path.ValidationPath, coverage: pyhanko.sign.validation.SignatureCoverageLevel, diff_result: Optional[Union[pyhanko.sign.diff_analysis.DiffResult, pyhanko.sign.diff_analysis.SuspiciousModification]], docmdp_ok: Optional[bool], signer_reported_dt: Optional[datetime.datetime] = None, timestamp_validity: Optional[pyhanko.sign.timestamps.TimestampSignatureStatus] = None, seed_value_constraint_error: Optional[pyhanko.sign.validation.SigSeedValueValidationError] = None)

Bases: pyhanko.sign.general.SignatureStatus

Class to indicate the validation status of a PDF signature.

coverage: pyhanko.sign.validation.SignatureCoverageLevel

Indicates how much of the document is covered by the signature.

diff_result: Optional[Union[pyhanko.sign.diff_analysis.DiffResult, pyhanko.sign.diff_analysis.SuspiciousModification]]

Result of the difference analysis run on the file:

  • If None, no difference analysis was run.

  • If the difference analysis was successful, this attribute will contain a DiffResult object.

  • If the difference analysis failed due to unforeseen or suspicious modifications, the SuspiciousModification exception thrown by the difference policy will be stored in this attribute.

docmdp_ok: Optional[bool]

Indicates whether the signature’s modification_level is in line with the document signature policy in force.

If None, compliance could not be determined.

signer_reported_dt: Optional[datetime.datetime] = None

Signer-reported signing time, if present in the signature.

Generally speaking, this timestamp should not be taken as fact.

timestamp_validity: Optional[pyhanko.sign.timestamps.TimestampSignatureStatus] = None

Validation status of the timestamp token embedded in this signature, if present.

seed_value_constraint_error: Optional[pyhanko.sign.validation.SigSeedValueValidationError] = None

Records the reason for failure if the signature field’s seed value constraints didn’t validate.

property modification_level

Indicates the degree to which the document was modified after the signature was applied.

Will be None if difference analysis results are not available; an instance of ModificationLevel otherwise.

property bottom_line

Formulates a general judgment on the validity of this signature. This takes into account the cryptographic validity of the signature, the signature’s chain of trust, compliance with the document modification policy, seed value constraint compliance and the validity of the timestamp token (if present).

Returns

True if all constraints are satisfied, False otherwise.

property seed_value_ok

Indicates whether the signature satisfies all mandatory constraints in the seed value dictionary of the associated form field.

Warning

Currently, not all seed value entries are recognised by the signer and/or the validator, so this judgment may not be entirely accurate in some cases.

See SigSeedValueSpec.

summary_fields()
pretty_print_details()
class pyhanko.sign.validation.EmbeddedPdfSignature(reader: pyhanko.pdf_utils.reader.PdfFileReader, sig_field: pyhanko.pdf_utils.generic.DictionaryObject, fq_name: str)

Bases: object

Class modelling a signature embedded in a PDF document.

sig_object: pyhanko.pdf_utils.generic.DictionaryObject

The signature dictionary.

sig_field: pyhanko.pdf_utils.generic.DictionaryObject

The field dictionary of the form field containing the signature.

signed_data: asn1crypto.cms.SignedData

CMS signed data in the signature.

signer_cert: asn1crypto.x509.Certificate

Certificate of the signer.

property field_name
Returns

Name of the signature field.

property self_reported_timestamp
Returns

The signing time as reported by the signer, if embedded in the signature’s signed attributes.

property external_timestamp_data
Returns

The signed data component of the timestamp token embedded in this signature, if present.

compute_integrity_info(diff_policy=None, skip_diff=False)

Compute the various integrity indicators of this signature.

Parameters
  • diff_policy – Policy to evaluate potential incremental updates that were appended to the signed revision of the document. Defaults to DEFAULT_DIFF_POLICY.

  • skip_diff – If True, skip the difference analysis step entirely.

summarise_integrity_info()dict

Compile the integrity information for this signature into a dictionary that can later be passed to PdfSignatureStatus as kwargs.

This method is only available after calling EmbeddedSig.compute_integrity_info().

property seed_value_spec
property docmdp_level
Returns

The document modification policy required by this signature.

Warning

This does not take into account the DocMDP requirements of earlier signatures (if present).

The specification forbids signing with a more lenient DocMDP than the one currently in force, so this should not happen in a compliant document. That being said, any potential violations will still invalidate the earlier signature with the stricter DocMDP policy.

property fieldmdp
Returns

Read the field locking policy of this signature, if applicable. See also FieldMDPSpec.

compute_digest()bytes

Compute the /ByteRange digest of this signature. The result will be cached.

Returns

The digest value.

compute_tst_digest()Optional[bytes]

Compute the digest of the signature needed to validate its timestamp token (if present).

Warning

This computation is only relevant for timestamp tokens embedded inside a regular signature. If the signature in question is a document timestamp (where the entire signature object is a timestamp token), this method does not apply.

Returns

The digest value, or None if there is no timestamp token.

evaluate_signature_coverage()pyhanko.sign.validation.SignatureCoverageLevel

Internal method used to evaluate the coverage level of a signature.

Returns

The coverage level of the signature.

evaluate_modifications(diff_policy: pyhanko.sign.diff_analysis.DiffPolicy)Union[pyhanko.sign.diff_analysis.DiffResult, pyhanko.sign.diff_analysis.SuspiciousModification]

Internal method used to evaluate the modification level of a signature.

class pyhanko.sign.validation.DocMDPInfo(permission, digest_method, author_sig)

Bases: tuple

Encodes certification information for a signed document, consisting of a reference to the author signature, together with the associated DocMDP policy.

property author_sig

Alias for field number 2

property digest_method

Alias for field number 1

property permission

Alias for field number 0

class pyhanko.sign.validation.RevocationInfoValidationType(value)

Bases: enum.Enum

Indicates a validation profile to use when validating revocation info.

ADOBE_STYLE = 'adobe'

Retrieve validation information from the CMS object, using Adobe’s revocation info archival attribute.

PADES_LT = 'pades'

Retrieve validation information from the DSS, and require the signature’s embedded timestamp to still be valid.

PADES_LTA = 'pades-lta'

Retrieve validation information from the DSS, but read & validate the chain of document timestamps leading up to the signature to establish the integrity of the validation information at the time of signing.

classmethod as_tuple()
class pyhanko.sign.validation.VRI(certs: set = <factory>, ocsps: set = <factory>, crls: set = <factory>)

Bases: object

VRI dictionary as defined in PAdES / ISO 32000-2. These dictionaries collect data that may be relevant for the validation of a specific signature.

Note

The data are stored as PDF indirect objects, not asn1crypto values. In particular, values are tied to a specific PDF handler.

certs: set

Relevant certificates.

ocsps: set

Relevant OCSP responses.

crls: set

Relevant CRLs.

as_pdf_object()pyhanko.pdf_utils.generic.DictionaryObject
Returns

A PDF dictionary representing this VRI entry.

class pyhanko.sign.validation.DocumentSecurityStore(writer, certs=None, ocsps=None, crls=None, vri_entries=None, backing_pdf_object=None)

Bases: object

Representation of a DSS in Python.

static sig_content_identifier(contents)pyhanko.pdf_utils.generic.NameObject

Hash the contents of a signature object to get the corresponding VRI identifier.

This is internal API.

Parameters

contents – Signature contents.

Returns

A name object to put into the DSS.

register_vri(identifier, *, certs=(), ocsps=(), crls=())

Register validation information for a set of signing certificates associated with a particular signature.

Parameters
  • identifier – Identifier of the signature object (see sig_content_identifier). If None, only embed the data into the DSS without associating it with any VRI.

  • certs – Certificates to add.

  • ocsps – OCSP responses to add.

  • crls – CRLs to add.

as_pdf_object()

Convert the DocumentSecurityStore object to a python dictionary. This method also handles DSS updates.

Returns

A PDF object representing this DSS.

as_validation_context(validation_context_kwargs, include_revinfo=True)certvalidator.context.ValidationContext

Construct a validation context from the data in this DSS.

Parameters
  • validation_context_kwargs – Extra kwargs to pass to the __init__ function.

  • include_revinfo – If False, revocation info is skipped.

Returns

A validation context preloaded with information from this DSS.

classmethod read_dss(handler: pyhanko.pdf_utils.rw_common.PdfHandler)pyhanko.sign.validation.DocumentSecurityStore

Read a DSS record from a file and add the data to a validation context.

Parameters

handler – PDF handler from which to read the DSS.

Returns

A DocumentSecurityStore object describing the current state of the DSS.

classmethod add_dss(output_stream, sig_contents, *, certs=None, ocsps=None, crls=None, paths=None, validation_context=None)

Add or update a DSS, and optionally associate the new information with a VRI entry tied to a signature object.

The result is applied to the output stream as an incremental update.

You can either specify the CMS objects to include directly, or pass them in as output from certvalidator.

Parameters
  • output_stream – Output stream to write to.

  • sig_contents – Contents of the new signature (used to compute the VRI hash). If None, the information will not be added to any VRI dictionary.

  • certs – Certificates to include in the VRI entry.

  • ocsps – OCSP responses to include in the VRI entry.

  • crls – CRLs to include in the VRI entry.

  • paths – Validation paths that have been established, and need to be added to the DSS.

  • validation_context – Validation context from which to draw OCSP responses and CRLs.

pyhanko.sign.validation.apply_adobe_revocation_info(signer_info: asn1crypto.cms.SignerInfo, validation_context_kwargs=None)certvalidator.context.ValidationContext

Read Adobe-style revocation information from a CMS object, and load it into a validation context.

Parameters
  • signer_info – Signer info CMS object.

  • validation_context_kwargs – Extra kwargs to pass to the __init__ function.

Returns

A validation context preloaded with the relevant revocation information.

pyhanko.sign.validation.read_certification_data(reader: pyhanko.pdf_utils.reader.PdfFileReader)Optional[pyhanko.sign.validation.DocMDPInfo]

Read the certification information for a PDF document, if present.

Parameters

reader – Reader representing the input document.

Returns

A DocMDPInfo object containing the relevant data, or None.

pyhanko.sign.validation.validate_pdf_ltv_signature(embedded_sig: pyhanko.sign.validation.EmbeddedPdfSignature, validation_type: pyhanko.sign.validation.RevocationInfoValidationType, validation_context_kwargs=None, bootstrap_validation_context=None, force_revinfo=False, diff_policy: Optional[pyhanko.sign.diff_analysis.DiffPolicy] = None, key_usage_settings: Optional[pyhanko.sign.general.KeyUsageConstraints] = None, skip_diff: bool = False)pyhanko.sign.validation.PdfSignatureStatus

Validate a PDF LTV signature according to a particular profile.

Parameters
  • embedded_sig – Embedded signature to evaluate.

  • validation_type – Validation profile to use.

  • validation_context_kwargs – Keyword args to instantiate certvalidator.ValidationContext objects needed over the course of the validation.

  • bootstrap_validation_context – Validation context used to validate the current timestamp.

  • force_revinfo – Require all certificates encountered to have some form of live revocation checking provisions.

  • diff_policy – Policy to evaluate potential incremental updates that were appended to the signed revision of the document. Defaults to DEFAULT_DIFF_POLICY.

  • key_usage_settings – A KeyUsageConstraints object specifying which key usage extensions must or must not be present in the signer’s certificate.

  • skip_diff – If True, skip the difference analysis step entirely.

Returns

The status of the signature.

pyhanko.sign.validation.validate_pdf_signature(embedded_sig: pyhanko.sign.validation.EmbeddedPdfSignature, signer_validation_context: Optional[certvalidator.context.ValidationContext] = None, ts_validation_context: Optional[certvalidator.context.ValidationContext] = None, diff_policy: Optional[pyhanko.sign.diff_analysis.DiffPolicy] = None, key_usage_settings: Optional[pyhanko.sign.general.KeyUsageConstraints] = None, skip_diff: bool = False)pyhanko.sign.validation.PdfSignatureStatus

Validate a PDF signature.

Parameters
  • embedded_sig – Embedded signature to evaluate.

  • signer_validation_context – Validation context to use to validate the signature’s chain of trust.

  • ts_validation_context – Validation context to use to validate the timestamp’s chain of trust (defaults to signer_validation_context).

  • diff_policy – Policy to evaluate potential incremental updates that were appended to the signed revision of the document. Defaults to DEFAULT_DIFF_POLICY.

  • key_usage_settings – A KeyUsageConstraints object specifying which key usage extensions must or must not be present in the signer’s certificate.

  • skip_diff – If True, skip the difference analysis step entirely.

Returns

The status of the PDF signature in question.

pyhanko.sign.validation.validate_cms_signature(signed_data: asn1crypto.cms.SignedData, status_cls: Type[StatusType] = <class 'pyhanko.sign.general.SignatureStatus'>, raw_digest: Optional[bytes] = None, validation_context: Optional[certvalidator.context.ValidationContext] = None, status_kwargs: Optional[dict] = None, key_usage_settings: Optional[pyhanko.sign.general.KeyUsageConstraints] = None, encap_data_invalid=False)

Validate a detached CMS signature (i.e. a SignedData object).

Parameters
  • signed_data – The asn1crypto.cms.SignedData object to validate.

  • status_cls – Status class to use for the validation result.

  • raw_digest – Raw digest, computed from context.

  • validation_context – Validation context to validate the signer’s certificate.

  • status_kwargs – Other keyword arguments to pass to the status_class when reporting validation results.

  • key_usage_settings – A KeyUsageConstraints object specifying which key usage extensions must or must not be present in the signer’s certificate.

  • encap_data_invalid

    If True, the encapsulated data inside the CMS is invalid, but the remaining validation logic still has to be run (e.g. a timestamp token, which requires validation of the embedded message imprint).

    This option is considered internal API, the semantics of which may change without notice in the future.

Returns

A SignatureStatus object (or an instance of a proper subclass)

exception pyhanko.sign.validation.ValidationInfoReadingError

Bases: ValueError

Error reading validation info.

exception pyhanko.sign.validation.SignatureValidationError

Bases: ValueError

Error validating a signature.

exception pyhanko.sign.validation.SigSeedValueValidationError(failure_message)

Bases: pyhanko.sign.validation.SignatureValidationError

Error validating a signature’s seed value constraints.

pyhanko.sign.validation.validate_sig_integrity(signer_info: asn1crypto.cms.SignedData, cert: asn1crypto.x509.Certificate, expected_content_type: str, actual_digest: bytes)Tuple[bool, bool]

Validate the integrity of a signature for a particular signerInfo object inside a CMS signed data container.

Warning

This function does not do any trust checks, and is considered “dangerous” API because it is easy to misuse.

Warning

This function currently does not deal with the case where signed attributes are absent.

Parameters
  • signer_info – A cms.SignerInfo object.

  • cert

    The signer’s certificate.

    Note

    This function will not attempt to extract certificates from the signed data.

  • expected_content_type – The expected value for the content type attribute (as a Python string, see cms.ContentType).

  • actual_digest – The actual digest to be matched to the message digest attribute.

Returns

A tuple of two booleans. The first indicates whether the provided digest matches the value in the signed attributes. The second indicates whether the signature of the digest is valid.