def test_no_field_type(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) out = signers.sign_pdf(w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, docmdp_permissions=fields.MDPPerm.FILL_FORMS), signer=FROM_CA, in_place=True) w = IncrementalPdfFileWriter(out) fields._insert_or_get_field_at( w, w.root['/AcroForm']['/Fields'], ('Blah', ), ) meta = signers.PdfSignatureMetadata(field_name='NewSig') out = signers.sign_pdf(w, meta, signer=FROM_CA) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' status = validate_pdf_signature( s, signer_validation_context=SIMPLE_V_CONTEXT()) assert status.modification_level == ModificationLevel.OTHER
def test_embed_with_af(incremental): if incremental: w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) else: r = PdfFileReader(BytesIO(MINIMAL)) w = writer.copy_into_new_writer(r) modified = datetime.now(tz=tzlocal.get_localzone()) created = modified - timedelta(days=1) ef_obj = embed.EmbeddedFileObject.from_file_data( w, data=VECTOR_IMAGE_PDF, params=embed.EmbeddedFileParams(creation_date=created, modification_date=modified)) spec = embed.FileSpec(file_spec_string='vector-test.pdf', embedded_data=ef_obj, description='Embedding test /w assoc file', af_relationship=generic.pdf_name('/Unspecified')) embed.embed_file(w, spec) out = BytesIO() w.write(out) r = PdfFileReader(out) assert r.input_version == (2, 0) emb_lst = r.root['/Names']['/EmbeddedFiles']['/Names'] assert len(emb_lst) == 2 assert emb_lst[0] == 'vector-test.pdf' spec_obj = emb_lst[1] assert '/UF' not in spec_obj assert spec_obj['/AFRelationship'] == '/Unspecified' stream = spec_obj['/EF']['/F'] assert stream.data == VECTOR_IMAGE_PDF assert '/UF' not in spec_obj['/EF'] assert r.root['/AF'].raw_get(0).reference == spec_obj.container_ref
def test_double_sig_fill_deep_field_post_sign(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) # create part of the structure already fields._insert_or_get_field_at( w, w.root['/AcroForm']['/Fields'], ('NewSigs', 'NewSig1'), field_obj=fields.SignatureFormField( 'NewSig1', include_on_page=w.root['/Pages']['/Kids'].raw_get(0))) out = signers.sign_pdf(w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, docmdp_permissions=fields.MDPPerm.FILL_FORMS), signer=FROM_CA, in_place=True) w = IncrementalPdfFileWriter(out) fqn = 'NewSigs.NewSig1' meta = signers.PdfSignatureMetadata(field_name=fqn) out = signers.sign_pdf(w, meta, signer=FROM_CA) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' val_trusted(s, extd=True) s = r.embedded_signatures[1] val_trusted(s)
def test_approval_sig(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) out = signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, ), signer=FROM_CA ) out.seek(0) w = IncrementalPdfFileWriter(out) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig2'), signer=FROM_CA ) out.seek(0) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' val_trusted(s, extd=True) info = read_certification_data(r) assert info.author_sig == s.sig_object.get_object() assert info.permission == pyhanko.sign.fields.MDPPerm.FILL_FORMS s = r.embedded_signatures[1] assert s.field_name == 'Sig2' val_trusted(s)
def test_overspecify_cms_digest_algo(): # TODO this behaviour is not ideal, but at least this test documents it signer = signers.SimpleSigner.load( CRYPTO_DATA_DIR + '/selfsigned.key.pem', CRYPTO_DATA_DIR + '/selfsigned.cert.pem', ca_chain_files=(CRYPTO_DATA_DIR + '/selfsigned.cert.pem',), key_passphrase=b'secret', # specify an algorithm object that also mandates a specific # message digest signature_mechanism=SignedDigestAlgorithm( {'algorithm': 'sha256_rsa'} ) ) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) # digest methods agree, so that should be OK out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig1', md_algorithm='sha256'), signer=signer ) r = PdfFileReader(out) s = r.embedded_signatures[0] val_untrusted(s) w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) with pytest.raises(SigningError): signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', md_algorithm='sha512' ), signer=signer )
def test_pades_dss_object_clobber(requests_mock): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_TWO_FIELDS)) meta1 = signers.PdfSignatureMetadata( field_name='Sig1', validation_context=live_testing_vc(requests_mock), subfilter=PADES, embed_validation_info=True, ) dummy_ref = w.add_object(generic.pdf_string("Hi there")).reference out = signers.sign_pdf(w, meta1, signer=FROM_CA, timestamper=DUMMY_TS) w = IncrementalPdfFileWriter(out) # We're going to reassign the DSS object to another object ID, namely # one that clobbers the dummy_ref object. This should be ample cause # for suspicion. dss = w.root['/DSS'] w.objects[(dummy_ref.generation, dummy_ref.idnum)] = dss w.root['/DSS'] = generic.IndirectObject(idnum=dummy_ref.idnum, generation=dummy_ref.generation, pdf=w) w.update_root() out = BytesIO() w.write(out) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' val_trusted_but_modified(s)
def test_pades_double_sign_delete_dss(requests_mock): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_TWO_FIELDS)) meta1 = signers.PdfSignatureMetadata( field_name='Sig1', validation_context=live_testing_vc(requests_mock), subfilter=PADES, embed_validation_info=True, ) meta2 = signers.PdfSignatureMetadata( field_name='Sig2', validation_context=live_testing_vc(requests_mock), subfilter=PADES, embed_validation_info=True, ) out = signers.sign_pdf(w, meta1, signer=FROM_CA, timestamper=DUMMY_TS) w = IncrementalPdfFileWriter(out) out = signers.sign_pdf(w, meta2, signer=FROM_CA, timestamper=DUMMY_TS) w = IncrementalPdfFileWriter(out) # DSS is now covered by the second signature, so this is illegal del w.root['/DSS'] w.update_root() out = BytesIO() w.write(out) r = PdfFileReader(out) assert '/DSS' not in r.root s = r.embedded_signatures[0] assert s.field_name == 'Sig1' val_trusted(s, extd=True) # however, the second signature is violated by the deletion of the /DSS key s = r.embedded_signatures[1] assert s.field_name == 'Sig2' val_trusted_but_modified(s)
def test_delete_signature(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_TWO_FIELDS)) # first, we simply sign the two fields out = signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=FROM_CA, existing_fields_only=True) w = IncrementalPdfFileWriter(out) out = signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig2'), signer=FROM_CA, existing_fields_only=True) # after that, we add an incremental update that deletes the first signature # This should invalidate the remaining one. w = IncrementalPdfFileWriter(out) sig_fields = fields.enumerate_sig_fields(w) field_name, sig_obj, sig_field = next(sig_fields) assert field_name == 'Sig1' del sig_field.get_object()['/V'] w.mark_update(sig_field) out = BytesIO() w.write(out) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig2' val_trusted_but_modified(s)
def test_pades_double_sign(requests_mock, certify_first): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_TWO_FIELDS)) meta1 = signers.PdfSignatureMetadata( field_name='Sig1', validation_context=live_testing_vc(requests_mock), subfilter=PADES, embed_validation_info=True, certify=certify_first) meta2 = signers.PdfSignatureMetadata( field_name='Sig2', validation_context=live_testing_vc(requests_mock), subfilter=PADES, embed_validation_info=True, ) out = signers.sign_pdf(w, meta1, signer=FROM_CA, timestamper=DUMMY_TS) w = IncrementalPdfFileWriter(out) out = signers.sign_pdf(w, meta2, signer=FROM_CA, timestamper=DUMMY_TS) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' if certify_first: assert len(s.sig_object['/Reference']) == 1 val_trusted(s, extd=True) s = r.embedded_signatures[1] assert s.field_name == 'Sig2' val_trusted(s, extd=True)
def test_double_sign_lock_second(): # test if the difference analysis correctly processes /Reference # on a newly added signature object w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) fields.append_signature_field(w, field_with_lock_sp(True)) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='SigFirst'), signer=FROM_CA, ) w = IncrementalPdfFileWriter(out) # now sign the locked field out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='SigNew'), signer=FROM_CA, ) r = PdfFileReader(out) s = r.embedded_signatures[0] val_trusted(s, extd=True) s = r.embedded_signatures[1] assert len(s.sig_object.get_object()['/Reference']) == 1 val_trusted(s)
def test_double_signature_tagged_file(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_TWO_FIELDS_TAGGED)) out = signers.sign_pdf(w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, docmdp_permissions=fields.MDPPerm.FILL_FORMS), signer=FROM_CA) # create a new signature field after signing w = IncrementalPdfFileWriter(out) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig2'), signer=FROM_CA, ) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' status = val_trusted(s, extd=True) assert status.modification_level == ModificationLevel.FORM_FILLING assert status.docmdp_ok s = r.embedded_signatures[1] assert s.field_name == 'Sig2' val_trusted(s)
def test_update_hybrid_twice(fname): with open(os.path.join(PDF_DATA_DIR, fname), 'rb') as inf: w = IncrementalPdfFileWriter(inf) t_obj = w.trailer['/Info'].raw_get('/Title') assert isinstance(t_obj, generic.IndirectObject) w.objects[(t_obj.generation, t_obj.idnum)] \ = generic.pdf_string('Updated') out = BytesIO() w.write(out) r = PdfFileReader(out) assert r.trailer['/Info']['/Title'] == 'Updated' container_info = r.xrefs.get_xref_container_info(1) assert container_info.xref_section_type == XRefSectionType.HYBRID_MAIN container_info = r.xrefs.get_xref_container_info(2) assert container_info.xref_section_type == XRefSectionType.STANDARD w = IncrementalPdfFileWriter(out) w.add_object(generic.pdf_string('This is an object')) w.write_in_place() r = PdfFileReader(out) assert '/XRefStm' not in r.trailer assert '/XRefStm' not in r.trailer_view assert r.trailer['/Info']['/Title'] == 'Updated' container_info = r.xrefs.get_xref_container_info(1) assert container_info.xref_section_type == XRefSectionType.HYBRID_MAIN container_info = r.xrefs.get_xref_container_info(2) assert container_info.xref_section_type == XRefSectionType.STANDARD container_info = r.xrefs.get_xref_container_info(3) assert container_info.xref_section_type == XRefSectionType.STANDARD
def test_http_timestamp(requests_mock): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) # bad content-type requests_mock.post(DUMMY_HTTP_TS.url, content=ts_response_callback) from pyhanko.sign.timestamps import TimestampRequestError with pytest.raises(TimestampRequestError): signers.sign_pdf( w, signers.PdfSignatureMetadata(), signer=FROM_CA, timestamper=DUMMY_HTTP_TS, existing_fields_only=True, ) requests_mock.post(DUMMY_HTTP_TS.url, content=ts_response_callback, headers={'Content-Type': 'application/timestamp-reply'}) w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(), signer=FROM_CA, timestamper=DUMMY_HTTP_TS, existing_fields_only=True, ) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' validity = val_trusted(s) assert validity.timestamp_validity is not None assert validity.timestamp_validity.trusted
def test_xref_null_update(): buf = BytesIO(MINIMAL) w = IncrementalPdfFileWriter(buf) w.write_in_place() r = PdfFileReader(buf) assert r.xrefs.total_revisions == 2 assert r.xrefs.explicit_refs_in_revision(1) == set()
def test_double_sig_add_visible_field(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) out = signers.sign_pdf(w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, docmdp_permissions=fields.MDPPerm.FILL_FORMS), signer=FROM_CA) # create a new signature field after signing w = IncrementalPdfFileWriter(out) sp = fields.SigFieldSpec('SigNew', box=(10, 74, 140, 134)) fields.append_signature_field(w, sp) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='SigNew'), signer=FROM_CA, ) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' status = val_trusted(s, extd=True) assert status.modification_level == ModificationLevel.FORM_FILLING assert status.docmdp_ok s = r.embedded_signatures[1] assert s.field_name == 'SigNew' val_trusted(s)
def test_append_sig_field_acro_update(): # test different configurations of the AcroForm w = PdfFileWriter() w.root['/AcroForm'] = generic.DictionaryObject( {pdf_name('/Fields'): generic.ArrayObject()}) w.insert_page(simple_page(w, 'Hello world')) out = BytesIO() w.write(out) out.seek(0) sp = fields.SigFieldSpec('InvisibleSig') w = IncrementalPdfFileWriter(out) fields.append_signature_field(w, sp) assert len(w.root['/AcroForm']['/Fields']) == 1 w = PdfFileWriter() # Technically, this is not standards-compliant, but our routine # shouldn't care w.root['/AcroForm'] = generic.DictionaryObject() w.insert_page(simple_page(w, 'Hello world')) out = BytesIO() w.write(out) out.seek(0) sp = fields.SigFieldSpec('InvisibleSig') w = IncrementalPdfFileWriter(out) with pytest.raises(ValueError): fields.append_signature_field(w, sp)
def test_double_sig_create_deep_field_post_sign(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) # create part of the structure already fields._insert_or_get_field_at( w, w.root['/AcroForm']['/Fields'], ('NewSigs', 'NewSig1'), field_obj=generic.DictionaryObject({pdf_name('/FT'): pdf_name('/Sig')})) out = signers.sign_pdf(w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, docmdp_permissions=fields.MDPPerm.FILL_FORMS), signer=FROM_CA, in_place=True) w = IncrementalPdfFileWriter(out) fqn = 'NewSigs.NewSig2' meta = signers.PdfSignatureMetadata(field_name=fqn) out = signers.sign_pdf(w, meta, signer=FROM_CA) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' status = validate_pdf_signature( s, signer_validation_context=SIMPLE_V_CONTEXT()) # the /Kids array of NewSigs was modified, which we don't allow (right now) assert status.modification_level == ModificationLevel.OTHER
def test_sign_with_new_field_spec(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) spec = fields.SigFieldSpec(sig_field_name='Sig1', box=(20, 20, 80, 40)) out = signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=FROM_CA, new_field_spec=spec) r = PdfFileReader(out) s = r.embedded_signatures[0] assert s.field_name == 'Sig1' assert '/AP' in s.sig_field w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) spec = fields.SigFieldSpec(sig_field_name='Sig1', box=(20, 20, 80, 40)) with pytest.raises(SigningError): signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig2'), signer=FROM_CA, new_field_spec=spec) with pytest.raises(SigningError): signers.sign_pdf(w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=FROM_CA, new_field_spec=spec, existing_fields_only=True)
def test_certify(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) out = signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', certify=True, docmdp_permissions=pyhanko.sign.fields.MDPPerm.NO_CHANGES ), signer=FROM_CA ) r = PdfFileReader(out) s = r.embedded_signatures[0] refs = s.sig_object.get_object()['/Reference'] assert len(refs) == 1 assert s.field_name == 'Sig1' val_trusted(s) info = read_certification_data(r) assert info.author_sig == s.sig_object.get_object() assert info.permission == pyhanko.sign.fields.MDPPerm.NO_CHANGES # with NO_CHANGES, we shouldn't be able to append an approval signature out.seek(0) w = IncrementalPdfFileWriter(out) with pytest.raises(SigningError): signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig2'), signer=FROM_CA )
def test_sign_with_revoked(requests_mock): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='Sig1'), signer=REVOKED_SIGNER ) r = PdfFileReader(out) s = r.embedded_signatures[0] vc = live_testing_vc(requests_mock) val_status = validate_pdf_signature(s, vc) assert val_status.intact assert val_status.valid assert val_status.revoked assert not val_status.trusted assert 'revoked' in val_status.pretty_print_details() summ = val_status.summary() assert 'INTACT' in summ assert 'REVOKED' in summ assert val_status.coverage == SignatureCoverageLevel.ENTIRE_FILE assert val_status.modification_level == ModificationLevel.NONE assert not val_status.bottom_line # should refuse to sign with a known revoked cert w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) with pytest.raises(SigningError): signers.sign_pdf( w, signers.PdfSignatureMetadata( field_name='Sig1', validation_context=vc ), signer=REVOKED_SIGNER )
def test_deep_modify(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) obj3 = generic.Reference(3, 0, w) deep_obj = w.get_object(obj3)['/Resources']['/Font']['/F1']['/Subtype'] assert deep_obj.container_ref.idnum == obj3.idnum w.update_container(deep_obj) assert (0, 3) in w.objects
def test_xref_stream_null_update(): buf = BytesIO(MINIMAL_XREF) w = IncrementalPdfFileWriter(buf) w.write_in_place() r = PdfFileReader(buf) assert r.xrefs.total_revisions == 2 # The xref stream itself got added assert len(r.xrefs.explicit_refs_in_revision(1)) == 1
def _stamp_file(input_name: str, output_name: str, style: TextStampStyle, stamp_class, dest_page: int, x: int, y: int, **stamp_kwargs): with open(input_name, 'rb') as fin: pdf_out = IncrementalPdfFileWriter(fin) stamp = stamp_class(writer=pdf_out, style=style, **stamp_kwargs) stamp.apply(dest_page, x, y) with open(output_name, 'wb') as out: pdf_out.write(out)
def test_not_all_paths_cleared(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD)) # make /Fields indirect fields_arr = w.root['/AcroForm'].raw_get('/Fields') # just in case we ever end up declaring /Fields as indirect in the example assert isinstance(fields_arr, generic.ArrayObject) w.root['/AcroForm']['/Fields'] = w.root['/Blah'] = w.add_object(fields_arr) w.update_root() w.update_container(w.root['/AcroForm']) out = signers.sign_pdf( w, signature_meta=signers.PdfSignatureMetadata(field_name='Sig1'), signer=FROM_CA) # create a new signature field after signing w = IncrementalPdfFileWriter(out) out = signers.sign_pdf( w, signers.PdfSignatureMetadata(field_name='SigNew'), signer=FROM_CA, ) r = PdfFileReader(out) val_trusted_but_modified(embedded_sig=r.embedded_signatures[0])
def add_dss(cls, output_stream, sig_contents, *, certs=None, ocsps=None, crls=None, paths=None, validation_context=None, force_write: bool = False, embed_roots: bool = True): """ Wrapper around :meth:`supply_dss_in_writer`. The result is applied to the output stream as an incremental update. :param output_stream: Output stream to write to. :param sig_contents: Contents of the new signature (used to compute the VRI hash), as as a hexadecimal string, including any padding. If ``None``, the information will not be added to any VRI dictionary. :param certs: Certificates to include in the VRI entry. :param ocsps: OCSP responses to include in the VRI entry. :param crls: CRLs to include in the VRI entry. :param paths: Validation paths that have been established, and need to be added to the DSS. :param force_write: Force a write even if the DSS doesn't have any new content. :param validation_context: Validation context from which to draw OCSP responses and CRLs. :param embed_roots: .. versionadded:: 0.9.0 Option that controls whether the root certificate of each validation path should be embedded into the DSS. The default is ``True``. .. note:: Trust roots are configured by the validator, so embedding them typically does nothing in a typical validation process. Therefore they can be safely omitted in most cases. Nonetheless, embedding the roots can be useful for documentation purposes. .. warning:: This only applies to paths, not the ``certs`` parameter. """ pdf_out = IncrementalPdfFileWriter(output_stream) dss = cls.supply_dss_in_writer( pdf_out, sig_contents, certs=certs, ocsps=ocsps, crls=crls, paths=paths, validation_context=validation_context, embed_roots=embed_roots ) if force_write or dss.modified: pdf_out.write_in_place()
def add_sig_field(infile, outfile, field): with pyhanko_exception_manager(): writer = IncrementalPdfFileWriter(infile) for s in field: name, spec = parse_field_location_spec(s) assert spec is not None fields.append_signature_field(writer, spec) writer.write(outfile) infile.close() outfile.close()
def test_sign_crypt_aes256(password): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_ONE_FIELD_AES256)) w.encrypt(password) out = signers.sign_pdf(w, signers.PdfSignatureMetadata(), signer=FROM_CA, existing_fields_only=True) r = PdfFileReader(out) r.decrypt(password) s = r.embedded_signatures[0] val_trusted(s)
def test_trailer_refs(): # This is a corner case in the reference handler that shouldn't really # come up in real life. That said, it's easy to test for using a (somewhat # contrived) example, so let's do that. w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) # Note: the container of the catalog is the thing root_ref points to, # but root_ref, when viewed as a PDF object by itself (i.e. the indirect # object embedded in the trailer) should have a TrailerReference as its # container. root_ref = w.trailer.raw_get('/Root') assert isinstance(root_ref.container_ref, generic.TrailerReference) w.update_container(root_ref)
def test_sign_crypt_pubkey_rc4(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL_PUBKEY_ONE_FIELD_RC4)) w.encrypt_pubkey(PUBKEY_SELFSIGNED_DECRYPTER) out = signers.sign_pdf(w, signers.PdfSignatureMetadata(), signer=FROM_CA, existing_fields_only=True) r = PdfFileReader(out) r.decrypt_pubkey(PUBKEY_SELFSIGNED_DECRYPTER) s = r.embedded_signatures[0] val_trusted(s)
def test_sign_with_empty_kids(): w = IncrementalPdfFileWriter(BytesIO(MINIMAL)) fields.append_signature_field( w, fields.SigFieldSpec( sig_field_name='Sig1', combine_annotation=False, box=(20, 20, 80, 40) ) ) w.root['/AcroForm']['/Fields'][0]['/Kids'] = generic.ArrayObject() meta = signers.PdfSignatureMetadata(field_name='Sig1') with pytest.raises(SigningError, match="Failed to access.*annot.*"): signers.sign_pdf(w, meta, signer=FROM_CA)