137 lines
3.5 KiB
Python
137 lines
3.5 KiB
Python
import click
|
|
from pyhanko_certvalidator import ValidationContext
|
|
|
|
from pyhanko.cli._trust import build_vc_kwargs, trust_options
|
|
from pyhanko.cli.commands.signing import signing
|
|
from pyhanko.cli.runtime import pyhanko_exception_manager
|
|
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
|
|
from pyhanko.pdf_utils.reader import PdfFileReader
|
|
from pyhanko.sign import signers, validation
|
|
from pyhanko.sign.timestamps import HTTPTimeStamper
|
|
|
|
__all__ = ['ltv_fix', 'lta_update']
|
|
|
|
|
|
@trust_options
|
|
@signing.command(name='ltaupdate', help='update LTA timestamp')
|
|
@click.argument('infile', type=click.File('r+b'))
|
|
@click.option(
|
|
'--timestamp-url',
|
|
help='URL for timestamp server',
|
|
required=True,
|
|
type=str,
|
|
default=None,
|
|
)
|
|
@click.option(
|
|
'--retroactive-revinfo',
|
|
help='Treat revocation info as retroactively valid '
|
|
'(i.e. ignore thisUpdate timestamp)',
|
|
type=bool,
|
|
is_flag=True,
|
|
default=False,
|
|
show_default=True,
|
|
)
|
|
@click.pass_context
|
|
def lta_update(
|
|
ctx,
|
|
infile,
|
|
validation_context,
|
|
trust,
|
|
trust_replace,
|
|
other_certs,
|
|
timestamp_url,
|
|
retroactive_revinfo,
|
|
):
|
|
with pyhanko_exception_manager():
|
|
vc_kwargs = build_vc_kwargs(
|
|
ctx.obj.config,
|
|
validation_context,
|
|
trust,
|
|
trust_replace,
|
|
other_certs,
|
|
retroactive_revinfo,
|
|
)
|
|
timestamper = HTTPTimeStamper(timestamp_url)
|
|
r = PdfFileReader(infile)
|
|
signers.PdfTimeStamper(timestamper).update_archival_timestamp_chain(
|
|
r, ValidationContext(**vc_kwargs)
|
|
)
|
|
|
|
|
|
# TODO perhaps add an option here to fix the lack of a timestamp and/or
|
|
# warn if none is present
|
|
|
|
|
|
@trust_options
|
|
@signing.command(
|
|
name='ltvfix', help='add revocation information for a signature to the DSS'
|
|
)
|
|
@click.argument('infile', type=click.File('r+b'))
|
|
@click.option('--field', help='name of the signature field', required=True)
|
|
@click.option(
|
|
'--timestamp-url',
|
|
help='URL for timestamp server',
|
|
required=False,
|
|
type=str,
|
|
default=None,
|
|
)
|
|
@click.option(
|
|
'--apply-lta-timestamp',
|
|
help='Apply a document timestamp after adding revocation info.',
|
|
required=False,
|
|
type=bool,
|
|
default=False,
|
|
is_flag=True,
|
|
show_default=True,
|
|
)
|
|
@click.pass_context
|
|
def ltv_fix(
|
|
ctx,
|
|
infile,
|
|
field,
|
|
timestamp_url,
|
|
apply_lta_timestamp,
|
|
validation_context,
|
|
trust_replace,
|
|
trust,
|
|
other_certs,
|
|
):
|
|
if apply_lta_timestamp and not timestamp_url:
|
|
raise click.ClickException(
|
|
"Please specify a timestamp server using --timestamp-url."
|
|
)
|
|
|
|
vc_kwargs = build_vc_kwargs(
|
|
ctx.obj.config,
|
|
validation_context,
|
|
trust,
|
|
trust_replace,
|
|
other_certs,
|
|
retroactive_revinfo=False,
|
|
allow_fetching=True,
|
|
)
|
|
vc_kwargs['revocation_mode'] = 'hard-fail'
|
|
r = PdfFileReader(infile)
|
|
|
|
try:
|
|
emb_sig = next(
|
|
s for s in r.embedded_regular_signatures if s.field_name == field
|
|
)
|
|
except StopIteration:
|
|
raise click.ClickException(
|
|
f"Could not find a PDF signature labelled {field}."
|
|
)
|
|
|
|
output = validation.add_validation_info(
|
|
emb_sig, ValidationContext(**vc_kwargs), in_place=True
|
|
)
|
|
|
|
if apply_lta_timestamp:
|
|
timestamper = HTTPTimeStamper(timestamp_url)
|
|
signers.PdfTimeStamper(timestamper).timestamp_pdf(
|
|
IncrementalPdfFileWriter(output),
|
|
signers.DEFAULT_MD,
|
|
ValidationContext(**vc_kwargs),
|
|
in_place=True,
|
|
)
|