387 lines
13 KiB
Python
387 lines
13 KiB
Python
import asyncio
|
|
import warnings
|
|
from typing import IO, Optional, TypeVar, Union
|
|
|
|
from asn1crypto import cms
|
|
from pyhanko_certvalidator import ValidationContext
|
|
|
|
from pyhanko.pdf_utils import misc
|
|
|
|
from ..diff_analysis import DiffPolicy
|
|
from .dss import (
|
|
VRI,
|
|
DocumentSecurityStore,
|
|
async_add_validation_info,
|
|
collect_validation_info,
|
|
)
|
|
from .errors import SigSeedValueValidationError, ValidationInfoReadingError
|
|
from .generic_cms import (
|
|
async_validate_cms_signature,
|
|
async_validate_detached_cms,
|
|
)
|
|
from .ltv import (
|
|
RevocationInfoValidationType,
|
|
apply_adobe_revocation_info,
|
|
async_validate_pdf_ltv_signature,
|
|
get_timestamp_chain,
|
|
)
|
|
from .pdf_embedded import (
|
|
DocMDPInfo,
|
|
EmbeddedPdfSignature,
|
|
async_validate_pdf_signature,
|
|
async_validate_pdf_timestamp,
|
|
read_certification_data,
|
|
)
|
|
from .settings import KeyUsageConstraints
|
|
from .status import (
|
|
DocumentTimestampStatus,
|
|
ModificationInfo,
|
|
PdfSignatureStatus,
|
|
SignatureCoverageLevel,
|
|
SignatureStatus,
|
|
StandardCMSSignatureStatus,
|
|
)
|
|
|
|
__all__ = [
|
|
'SignatureCoverageLevel',
|
|
'PdfSignatureStatus',
|
|
'DocumentTimestampStatus',
|
|
'StandardCMSSignatureStatus',
|
|
'ModificationInfo',
|
|
'EmbeddedPdfSignature',
|
|
'DocMDPInfo',
|
|
'RevocationInfoValidationType',
|
|
'VRI',
|
|
'DocumentSecurityStore',
|
|
'apply_adobe_revocation_info',
|
|
'get_timestamp_chain',
|
|
'read_certification_data',
|
|
'validate_pdf_signature',
|
|
'async_validate_pdf_signature',
|
|
'validate_cms_signature',
|
|
'async_validate_cms_signature',
|
|
'validate_detached_cms',
|
|
'async_validate_detached_cms',
|
|
'validate_pdf_timestamp',
|
|
'async_validate_pdf_timestamp',
|
|
'validate_pdf_ltv_signature',
|
|
'async_validate_pdf_ltv_signature',
|
|
'collect_validation_info',
|
|
'add_validation_info',
|
|
]
|
|
|
|
|
|
StatusType = TypeVar('StatusType', bound=SignatureStatus)
|
|
|
|
|
|
# noinspection PyUnusedLocal
|
|
def validate_cms_signature(
|
|
signed_data: cms.SignedData,
|
|
status_cls=SignatureStatus,
|
|
raw_digest: Optional[bytes] = None,
|
|
validation_context: Optional[ValidationContext] = None,
|
|
status_kwargs: Optional[dict] = None,
|
|
key_usage_settings: Optional[KeyUsageConstraints] = None,
|
|
encap_data_invalid=False,
|
|
):
|
|
"""
|
|
.. deprecated:: 0.9.0
|
|
Use :func:`~.generic_cms.async_validate_cms_signature` instead.
|
|
|
|
.. versionchanged:: 0.7.0
|
|
Now handles both detached and enveloping signatures.
|
|
|
|
.. versionchanged:: 0.17.0
|
|
The ``encap_data_invalid`` parameter is ignored.
|
|
|
|
Validate a CMS signature (i.e. a ``SignedData`` object).
|
|
|
|
:param signed_data:
|
|
The :class:`.asn1crypto.cms.SignedData` object to validate.
|
|
:param status_cls:
|
|
Status class to use for the validation result.
|
|
:param raw_digest:
|
|
Raw digest, computed from context.
|
|
:param validation_context:
|
|
Validation context to validate the signer's certificate.
|
|
:param status_kwargs:
|
|
Other keyword arguments to pass to the ``status_class`` when reporting
|
|
validation results.
|
|
:param key_usage_settings:
|
|
A :class:`.KeyUsageConstraints` object specifying which key usages
|
|
must or must not be present in the signer's certificate.
|
|
:param encap_data_invalid:
|
|
As of version ``0.17.0``, this parameter is ignored.
|
|
:return:
|
|
A :class:`.SignatureStatus` object (or an instance of a proper subclass)
|
|
"""
|
|
|
|
warnings.warn(
|
|
"'validate_cms_signature' is deprecated, use "
|
|
"'async_validate_cms_signature' instead",
|
|
DeprecationWarning,
|
|
)
|
|
|
|
coro = async_validate_cms_signature(
|
|
signed_data=signed_data,
|
|
status_cls=status_cls,
|
|
raw_digest=raw_digest,
|
|
validation_context=validation_context,
|
|
status_kwargs=status_kwargs,
|
|
key_usage_settings=key_usage_settings,
|
|
)
|
|
return asyncio.run(coro)
|
|
|
|
|
|
def validate_detached_cms(
|
|
input_data: Union[bytes, IO, cms.ContentInfo, cms.EncapsulatedContentInfo],
|
|
signed_data: cms.SignedData,
|
|
signer_validation_context: Optional[ValidationContext] = None,
|
|
ts_validation_context: Optional[ValidationContext] = None,
|
|
key_usage_settings: Optional[KeyUsageConstraints] = None,
|
|
chunk_size=misc.DEFAULT_CHUNK_SIZE,
|
|
max_read=None,
|
|
) -> StandardCMSSignatureStatus:
|
|
"""
|
|
.. deprecated:: 0.9.0
|
|
Use :func:`.generic_cms.async_validate_detached_cms` instead.
|
|
|
|
.. versionadded: 0.7.0
|
|
|
|
Validate a detached CMS signature.
|
|
|
|
:param input_data:
|
|
The input data to sign. This can be either a :class:`bytes` object,
|
|
a file-like object or a :class:`cms.ContentInfo` /
|
|
:class:`cms.EncapsulatedContentInfo` object.
|
|
|
|
If a CMS content info object is passed in, the `content` field
|
|
will be extracted.
|
|
:param signed_data:
|
|
The :class:`cms.SignedData` object containing the signature to verify.
|
|
:param signer_validation_context:
|
|
Validation context to use to verify the signer certificate's trust.
|
|
:param ts_validation_context:
|
|
Validation context to use to verify the TSA certificate's trust, if
|
|
a timestamp token is present.
|
|
By default, the same validation context as that of the signer is used.
|
|
:param key_usage_settings:
|
|
Key usage parameters for the signer.
|
|
:param chunk_size:
|
|
Chunk size to use when consuming input data.
|
|
:param max_read:
|
|
Maximal number of bytes to read from the input stream.
|
|
:return:
|
|
A description of the signature's status.
|
|
"""
|
|
|
|
warnings.warn(
|
|
"'validate_detached_cms' is deprecated, use "
|
|
"'async_validate_detached_cms' instead",
|
|
DeprecationWarning,
|
|
)
|
|
|
|
coro = async_validate_detached_cms(
|
|
input_data=input_data,
|
|
signed_data=signed_data,
|
|
signer_validation_context=signer_validation_context,
|
|
ts_validation_context=ts_validation_context,
|
|
key_usage_settings=key_usage_settings,
|
|
chunk_size=chunk_size,
|
|
max_read=max_read,
|
|
)
|
|
return asyncio.run(coro)
|
|
|
|
|
|
def validate_pdf_signature(
|
|
embedded_sig: EmbeddedPdfSignature,
|
|
signer_validation_context: Optional[ValidationContext] = None,
|
|
ts_validation_context: Optional[ValidationContext] = None,
|
|
diff_policy: Optional[DiffPolicy] = None,
|
|
key_usage_settings: Optional[KeyUsageConstraints] = None,
|
|
skip_diff: bool = False,
|
|
) -> PdfSignatureStatus:
|
|
"""
|
|
.. versionchanged:: 0.9.0
|
|
Wrapper around :func:`~.pdf_embedded.async_validate_pdf_signature`.
|
|
|
|
Validate a PDF signature.
|
|
|
|
:param embedded_sig:
|
|
Embedded signature to evaluate.
|
|
:param signer_validation_context:
|
|
Validation context to use to validate the signature's chain of trust.
|
|
:param ts_validation_context:
|
|
Validation context to use to validate the timestamp's chain of trust
|
|
(defaults to ``signer_validation_context``).
|
|
:param diff_policy:
|
|
Policy to evaluate potential incremental updates that were appended
|
|
to the signed revision of the document.
|
|
Defaults to
|
|
:const:`~pyhanko.sign.diff_analysis.DEFAULT_DIFF_POLICY`.
|
|
:param key_usage_settings:
|
|
A :class:`.KeyUsageConstraints` object specifying which key usages
|
|
must or must not be present in the signer's certificate.
|
|
:param skip_diff:
|
|
If ``True``, skip the difference analysis step entirely.
|
|
:return:
|
|
The status of the PDF signature in question.
|
|
"""
|
|
coro = async_validate_pdf_signature(
|
|
embedded_sig=embedded_sig,
|
|
signer_validation_context=signer_validation_context,
|
|
ts_validation_context=ts_validation_context,
|
|
diff_policy=diff_policy,
|
|
key_usage_settings=key_usage_settings,
|
|
skip_diff=skip_diff,
|
|
)
|
|
return asyncio.run(coro)
|
|
|
|
|
|
def validate_pdf_timestamp(
|
|
embedded_sig: EmbeddedPdfSignature,
|
|
validation_context: Optional[ValidationContext] = None,
|
|
diff_policy: Optional[DiffPolicy] = None,
|
|
skip_diff: bool = False,
|
|
) -> DocumentTimestampStatus:
|
|
"""
|
|
.. versionchanged:: 0.9.0
|
|
Wrapper around :func:`~.pdf_embedded.async_validate_pdf_timestamp`.
|
|
|
|
Validate a PDF document timestamp.
|
|
|
|
:param embedded_sig:
|
|
Embedded signature to evaluate.
|
|
:param validation_context:
|
|
Validation context to use to validate the timestamp's chain of trust.
|
|
:param diff_policy:
|
|
Policy to evaluate potential incremental updates that were appended
|
|
to the signed revision of the document.
|
|
Defaults to
|
|
:const:`~pyhanko.sign.diff_analysis.DEFAULT_DIFF_POLICY`.
|
|
:param skip_diff:
|
|
If ``True``, skip the difference analysis step entirely.
|
|
:return:
|
|
The status of the PDF timestamp in question.
|
|
"""
|
|
coro = async_validate_pdf_timestamp(
|
|
embedded_sig=embedded_sig,
|
|
validation_context=validation_context,
|
|
diff_policy=diff_policy,
|
|
skip_diff=skip_diff,
|
|
)
|
|
return asyncio.run(coro)
|
|
|
|
|
|
def add_validation_info(
|
|
embedded_sig: EmbeddedPdfSignature,
|
|
validation_context: ValidationContext,
|
|
skip_timestamp=False,
|
|
add_vri_entry=True,
|
|
in_place=False,
|
|
output=None,
|
|
force_write=False,
|
|
chunk_size=misc.DEFAULT_CHUNK_SIZE,
|
|
):
|
|
"""
|
|
.. versionchanged:: 0.9.0
|
|
Wrapper around :func:`~.dss.async_add_validation_info`
|
|
|
|
Add validation info (CRLs, OCSP responses, extra certificates) for a
|
|
signature to the DSS of a document in an incremental update.
|
|
|
|
:param embedded_sig:
|
|
The signature for which the revocation information needs to be
|
|
collected.
|
|
:param validation_context:
|
|
The validation context to use.
|
|
:param skip_timestamp:
|
|
If ``True``, do not attempt to validate the timestamp attached to
|
|
the signature, if one is present.
|
|
:param add_vri_entry:
|
|
Add a ``/VRI`` entry for this signature to the document security store.
|
|
Default is ``True``.
|
|
:param output:
|
|
Write the output to the specified output stream.
|
|
If ``None``, write to a new :class:`.BytesIO` object.
|
|
Default is ``None``.
|
|
:param in_place:
|
|
Sign the original input stream in-place.
|
|
This parameter overrides ``output``.
|
|
:param chunk_size:
|
|
Chunk size parameter to use when copying output to a new stream
|
|
(irrelevant if ``in_place`` is ``True``).
|
|
:param force_write:
|
|
Force a new revision to be written, even if not necessary (i.e.
|
|
when all data in the validation context is already present in the DSS).
|
|
:return:
|
|
The (file-like) output object to which the result was written.
|
|
"""
|
|
|
|
coro = async_add_validation_info(
|
|
embedded_sig=embedded_sig,
|
|
validation_context=validation_context,
|
|
skip_timestamp=skip_timestamp,
|
|
add_vri_entry=add_vri_entry,
|
|
output=output,
|
|
in_place=in_place,
|
|
chunk_size=chunk_size,
|
|
force_write=force_write,
|
|
)
|
|
return asyncio.run(coro)
|
|
|
|
|
|
def validate_pdf_ltv_signature(
|
|
embedded_sig: EmbeddedPdfSignature,
|
|
validation_type: RevocationInfoValidationType,
|
|
validation_context_kwargs=None,
|
|
bootstrap_validation_context=None,
|
|
force_revinfo=False,
|
|
diff_policy: Optional[DiffPolicy] = None,
|
|
key_usage_settings: Optional[KeyUsageConstraints] = None,
|
|
skip_diff: bool = False,
|
|
) -> PdfSignatureStatus:
|
|
"""
|
|
.. versionchanged:: 0.9.0
|
|
Wrapper around :func:`async_validate_pdf_ltv_signature`.
|
|
|
|
Validate a PDF LTV signature according to a particular profile.
|
|
|
|
:param embedded_sig:
|
|
Embedded signature to evaluate.
|
|
:param validation_type:
|
|
Validation profile to use.
|
|
:param validation_context_kwargs:
|
|
Keyword args to instantiate
|
|
:class:`.pyhanko_certvalidator.ValidationContext` objects needed over
|
|
the course of the validation.
|
|
:param bootstrap_validation_context:
|
|
Validation context used to validate the current timestamp.
|
|
:param force_revinfo:
|
|
Require all certificates encountered to have some form of live
|
|
revocation checking provisions.
|
|
:param diff_policy:
|
|
Policy to evaluate potential incremental updates that were appended
|
|
to the signed revision of the document.
|
|
Defaults to
|
|
:const:`~pyhanko.sign.diff_analysis.DEFAULT_DIFF_POLICY`.
|
|
:param key_usage_settings:
|
|
A :class:`.KeyUsageConstraints` object specifying which key usages
|
|
must or must not be present in the signer's certificate.
|
|
:param skip_diff:
|
|
If ``True``, skip the difference analysis step entirely.
|
|
:return:
|
|
The status of the signature.
|
|
"""
|
|
coro = async_validate_pdf_ltv_signature(
|
|
embedded_sig=embedded_sig,
|
|
validation_type=validation_type,
|
|
validation_context_kwargs=validation_context_kwargs,
|
|
bootstrap_validation_context=bootstrap_validation_context,
|
|
force_revinfo=force_revinfo,
|
|
diff_policy=diff_policy,
|
|
key_usage_settings=key_usage_settings,
|
|
skip_diff=skip_diff,
|
|
)
|
|
return asyncio.run(coro)
|