pyhanko.sign.diff_analysis.rules package
Submodules
pyhanko.sign.diff_analysis.rules.file_structure_rules module
- class pyhanko.sign.diff_analysis.rules.file_structure_rules.CatalogModificationRule(ignored_keys=None)
Bases:
QualifiedWhitelistRule
Rule that adjudicates modifications to the document catalog.
- Parameters:
ignored_keys –
Values in the document catalog that may change between revisions. The default ones are
/AcroForm
,/DSS
,/Extensions
,/Metadata
,/MarkInfo
and/Version
.Checking for
/AcroForm
,/DSS
and/Metadata
is delegated toFormUpdatingRule
,DSSCompareRule
andMetadataUpdateRule
, respectively.
- apply_qualified(old: HistoricalResolver, new: HistoricalResolver) Iterable[Tuple[ModificationLevel, ReferenceUpdate]]
Apply the rule to the changes between two revisions.
- Parameters:
old – The older, base revision.
new – The newer revision to be vetted.
- class pyhanko.sign.diff_analysis.rules.file_structure_rules.ObjectStreamRule
Bases:
WhitelistRule
Rule that allows object streams to be added.
Note that this rule only whitelists the object streams themselves (provided they do not override any existing objects, obviously), not the objects in them.
- apply(old: HistoricalResolver, new: HistoricalResolver) Iterable[ReferenceUpdate]
Apply the rule to the changes between two revisions.
- Parameters:
old – The older, base revision.
new – The newer revision to be vetted.
- class pyhanko.sign.diff_analysis.rules.file_structure_rules.XrefStreamRule
Bases:
WhitelistRule
Rule that allows new cross-reference streams to be defined.
- apply(old: HistoricalResolver, new: HistoricalResolver) Iterable[ReferenceUpdate]
Apply the rule to the changes between two revisions.
- Parameters:
old – The older, base revision.
new – The newer revision to be vetted.
pyhanko.sign.diff_analysis.rules.form_field_rules module
- class pyhanko.sign.diff_analysis.rules.form_field_rules.DSSCompareRule
Bases:
WhitelistRule
Rule that allows changes to the document security store (DSS).
This rule will validate the structure of the DSS quite rigidly, and will raise
SuspiciousModification
whenever it encounters structural problems with the DSS. Similarly, modifications that remove structural items from the DSS also count as suspicious. However, merely removing individual OCSP responses, CRLs or certificates when they become irrelevant is permitted. This is also allowed by PAdES.- apply(old: HistoricalResolver, new: HistoricalResolver) Iterable[ReferenceUpdate]
Apply the rule to the changes between two revisions.
- Parameters:
old – The older, base revision.
new – The newer revision to be vetted.
- class pyhanko.sign.diff_analysis.rules.form_field_rules.SigFieldCreationRule(approve_widget_bindings=True, allow_new_visible_after_certify=False)
Bases:
FieldMDPRule
This rule allows signature fields to be created at the root of the form hierarchy, but disallows the creation of other types of fields. It also disallows field deletion.
In addition, this rule will allow newly created signature fields to attach themselves as widget annotations to pages.
The creation of invisible signature fields is considered a modification at level
ModificationLevel.LTA_UPDATES
, but appearance-related changes will be qualified withModificationLevel.FORM_FILLING
.- Parameters:
allow_new_visible_after_certify – Creating new visible signature fields is disallowed after certification signatures by default; this is stricter than Acrobat. Set this parameter to
True
to disable this check.approve_widget_bindings – Set to
False
to reject new widget annotation registrations associated with approved new fields.
- apply(context: FieldComparisonContext) Iterable[Tuple[ModificationLevel, FormUpdate]]
Apply the rule to the given
FieldComparisonContext
.- Parameters:
context – The context of this form revision evaluation, given as an instance of
FieldComparisonContext
.
- class pyhanko.sign.diff_analysis.rules.form_field_rules.SigFieldModificationRule(allow_in_place_appearance_stream_changes: bool = True, always_modifiable=None, value_update_keys=None)
Bases:
BaseFieldModificationRule
This rule allows signature fields to be filled in, and set an appearance if desired. Deleting values from signature fields is disallowed, as is modifying signature fields that already contain a signature.
This rule will take field locks into account if the
FieldComparisonContext
includes aFieldMDPSpec
.For (invisible) document timestamps, this is allowed at
ModificationLevel.LTA_UPDATES
, but in all other cases the modification level will be bumped toModificationLevel.FORM_FILLING
.- check_form_field(fq_name: str, spec: FieldComparisonSpec, context: FieldComparisonContext) Iterable[Tuple[ModificationLevel, FormUpdate]]
Investigate updates to a particular form field. This function is called by
apply()
for every form field in the new revision.- Parameters:
fq_name – The fully qualified name of the form field.j
spec – The
FieldComparisonSpec
object describing the old state of the field in relation to the new state.context – The full
FieldComparisonContext
that is currently being evaluated.
- Returns:
An iterable yielding
FormUpdate
objects qualified with an appropriateModificationLevel
.
- class pyhanko.sign.diff_analysis.rules.form_field_rules.GenericFieldModificationRule(allow_in_place_appearance_stream_changes: bool = True, always_modifiable=None, value_update_keys=None)
Bases:
BaseFieldModificationRule
This rule allows non-signature form fields to be modified at
ModificationLevel.FORM_FILLING
.This rule will take field locks into account if the
FieldComparisonContext
includes aFieldMDPSpec
.- check_form_field(fq_name: str, spec: FieldComparisonSpec, context: FieldComparisonContext) Iterable[Tuple[ModificationLevel, FormUpdate]]
Investigate updates to a particular form field. This function is called by
apply()
for every form field in the new revision.- Parameters:
fq_name – The fully qualified name of the form field.j
spec – The
FieldComparisonSpec
object describing the old state of the field in relation to the new state.context – The full
FieldComparisonContext
that is currently being evaluated.
- Returns:
An iterable yielding
FormUpdate
objects qualified with an appropriateModificationLevel
.
- class pyhanko.sign.diff_analysis.rules.form_field_rules.BaseFieldModificationRule(allow_in_place_appearance_stream_changes: bool = True, always_modifiable=None, value_update_keys=None)
Bases:
FieldMDPRule
Base class that implements some boilerplate to validate modifications to individual form fields.
- compare_fields(spec: FieldComparisonSpec) bool
Helper method to compare field dictionaries.
- Parameters:
spec – The current
FieldComparisonSpec
.- Returns:
True
if the modifications are permissible even when the field is locked,False
otherwise. If keys beyond those invalue_update_keys
are changed, aSuspiciousModification
is raised.
- apply(context: FieldComparisonContext) Iterable[Tuple[ModificationLevel, FormUpdate]]
Apply the rule to the given
FieldComparisonContext
.- Parameters:
context – The context of this form revision evaluation, given as an instance of
FieldComparisonContext
.
- check_form_field(fq_name: str, spec: FieldComparisonSpec, context: FieldComparisonContext) Iterable[Tuple[ModificationLevel, FormUpdate]]
Investigate updates to a particular form field. This function is called by
apply()
for every form field in the new revision.- Parameters:
fq_name – The fully qualified name of the form field.j
spec – The
FieldComparisonSpec
object describing the old state of the field in relation to the new state.context – The full
FieldComparisonContext
that is currently being evaluated.
- Returns:
An iterable yielding
FormUpdate
objects qualified with an appropriateModificationLevel
.
pyhanko.sign.diff_analysis.rules.metadata_rules module
- class pyhanko.sign.diff_analysis.rules.metadata_rules.DocInfoRule
Bases:
WhitelistRule
Rule that allows the
/Info
dictionary in the trailer to be updated.- apply(old: HistoricalResolver, new: HistoricalResolver) Iterable[ReferenceUpdate]
Apply the rule to the changes between two revisions.
- Parameters:
old – The older, base revision.
new – The newer revision to be vetted.
- class pyhanko.sign.diff_analysis.rules.metadata_rules.MetadataUpdateRule(check_xml_syntax=True, always_refuse_stream_override=False)
Bases:
WhitelistRule
Rule to adjudicate updates to the XMP metadata stream.
The content of the metadata isn’t actually validated in any significant way; this class only checks whether the XML is well-formed.
- Parameters:
check_xml_syntax – Do a well-formedness check on the XML syntax. Default
True
.always_refuse_stream_override –
Always refuse to override the metadata stream if its object ID existed in a prior revision, including if the new stream overrides the old metadata stream and the syntax check passes. Default
False
.Note
In other situations, pyHanko will reject stream overrides on general principle, since combined with the fault-tolerance of some PDF readers, these can allow an attacker to manipulate parts of the signed content in subtle but significant ways.
In case of the metadata stream, the risk is significantly mitigated thanks to the XML syntax check on both versions of the stream, but if you’re feeling extra paranoid, you can turn the default behaviour back on by setting
always_refuse_stream_override
toTrue
.
- static is_well_formed_xml(metadata_ref: Reference)
Checks whether the provided stream consists of well-formed XML data. Note that this does not perform any more advanced XML or XMP validation, the check is purely syntactic.
- Parameters:
metadata_ref – A reference to a (purported) metadata stream.
- Raises:
SuspiciousModification – if there are indications that the reference doesn’t point to an XML stream.
- apply(old: HistoricalResolver, new: HistoricalResolver) Iterable[ReferenceUpdate]
Apply the rule to the changes between two revisions.
- Parameters:
old – The older, base revision.
new – The newer revision to be vetted.
Module contents
Rule implementations for the standard difference analysis policy.