Digitally Sign PDF Files - DigitalSignatures

Sample code to use Apryse SDK's high-level digital signature API for digitally signing and/or certifying PDF files; provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.. Learn more about our Server SDK and PDF Digital Signature Library.

1#!/usr/bin/python
2
3#-----------------------------------------------------------------------------------------------------------------------
4# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
5# Consult LICENSE.txt regarding license information.
6#-----------------------------------------------------------------------------------------------------------------------
7
8##----------------------------------------------------------------------------------------------------------------------
9## This sample demonstrates the basic usage of the high-level digital signatures API in PDFNet.
10##
11## The following steps reflect typical intended usage of the digital signatures API:
12##
13## 0. Start with a PDF with or without form fields in it that one would like to lock (or, one can add a field, see (1)).
14##
15## 1. EITHER:
16## (a) Call doc.CreateDigitalSignatureField, optionally providing a name. You receive a DigitalSignatureField.
17## -OR-
18## (b) If you didn't just create the digital signature field that you want to sign/certify, find the existing one within the
19## document by using PDFDoc.DigitalSignatureFieldIterator or by using PDFDoc.GetField to get it by its fully qualified name.
20##
21## 2. Create a signature widget annotation, and pass the DigitalSignatureField that you just created or found.
22## If you want it to be visible, provide a Rect argument with a non-zero width or height, and don't set the
23## NoView and Hidden flags. [Optionally, add an appearance to the annotation when you wish to sign/certify.]
24##
25## [3. (OPTIONAL) Add digital signature restrictions to the document using the field modification permissions (SetFieldPermissions)
26## or document modification permissions functions (SetDocumentPermissions) of DigitalSignatureField. These features disallow
27## certain types of changes to be made to the document without invalidating the cryptographic digital signature once it
28## is signed.]
29##
30## 4. Call either CertifyOnNextSave or SignOnNextSave. There are three overloads for each one (six total):
31## a. Taking a PKCS #12 keyfile path and its password
32## b. Taking a buffer containing a PKCS #12 private keyfile and its password
33## c. Taking a unique identifier of a signature handler registered with the PDFDoc. This overload is to be used
34## in the following fashion:
35## i) Extend and implement a new SignatureHandler. The SignatureHandler will be used to add or
36## validate/check a digital signature.
37## ii) Create an instance of the implemented SignatureHandler and register it with PDFDoc with
38## pdfdoc.AddSignatureHandler(). The method returns a SignatureHandlerId.
39## iii) Call SignOnNextSaveWithCustomHandler/CertifyOnNextSaveWithCustomHandler with the SignatureHandlerId.
40## NOTE: It is only possible to sign/certify one signature per call to the Save function.
41##
42## 5. Call pdfdoc.Save(). This will also create the digital signature dictionary and write a cryptographic signature to it.
43## IMPORTANT: If there are already signed/certified digital signature(s) in the document, you must save incrementally
44## so as to not invalidate the other signature(s).
45##
46## Additional processing can be done before document is signed. For example, UseSignatureHandler() returns an instance
47## of SDF dictionary which represents the signature dictionary (or the /V entry of the form field). This can be used to
48## add additional information to the signature dictionary (e.g. Name, Reason, Location, etc.).
49##
50## Although the steps above describes extending the SignatureHandler class, this sample demonstrates the use of
51## StdSignatureHandler (a built-in SignatureHandler in PDFNet) to sign a PDF file.
52##----------------------------------------------------------------------------------------------------------------------
53
54
55import site
56site.addsitedir("../../../PDFNetC/Lib")
57import sys
58from PDFNetPython import *
59
60sys.path.append("../../LicenseKey/PYTHON")
61from LicenseKey import *
62
63def VerifySimple(in_docpath, in_public_key_file_path):
64 doc = PDFDoc(in_docpath)
65 print("==========")
66 opts = VerificationOptions(VerificationOptions.e_compatibility_and_archiving)
67
68 # Add trust root to store of trusted certificates contained in VerificationOptions.
69 opts.AddTrustedCertificate(in_public_key_file_path, VerificationOptions.e_default_trust | VerificationOptions.e_certification_trust)
70
71 result = doc.VerifySignedDigitalSignatures(opts)
72
73 if result is PDFDoc.e_unsigned:
74 print("Document has no signed signature fields.")
75 return False
76 # e_failure == bad doc status, digest status, or permissions status
77 # (i.e. does not include trust issues, because those are flaky due to being network/config-related)
78 elif result is PDFDoc.e_failure:
79 print("Hard failure in verification on at least one signature.")
80 return False
81 elif result is PDFDoc.e_untrusted:
82 print("Could not verify trust for at least one signature.")
83 return False
84 elif result is PDFDoc.e_unsupported:
85 # If necessary, call GetUnsupportedFeatures on VerificationResult to check which
86 # unsupported features were encountered (requires verification using 'detailed' APIs)
87 print("At least one signature contains unsupported features.")
88 return False
89 # unsigned sigs skipped; parts of document may be unsigned (check GetByteRanges on signed sigs to find out)
90 elif result is PDFDoc.e_verified:
91 print("All signed signatures in document verified.")
92 return True
93 else:
94 print("unrecognized document verification status")
95 assert False, "unrecognized document status"
96
97
98def VerifyAllAndPrint(in_docpath, in_public_key_file_path):
99 doc = PDFDoc(in_docpath)
100 print("==========")
101 opts = VerificationOptions(VerificationOptions.e_compatibility_and_archiving)
102
103 # Trust the public certificate we use for signing.
104 trusted_cert_buf = []
105 trusted_cert_file = MappedFile(in_public_key_file_path)
106 file_sz = trusted_cert_file.FileSize()
107 file_reader = FilterReader(trusted_cert_file)
108 trusted_cert_buf = file_reader.Read(file_sz)
109 opts.AddTrustedCertificate(trusted_cert_buf, len(trusted_cert_buf), VerificationOptions.e_default_trust | VerificationOptions.e_certification_trust)
110
111 # Iterate over the signatures and verify all of them.
112 digsig_fitr = doc.GetDigitalSignatureFieldIterator()
113 verification_status = True
114 while (digsig_fitr.HasNext()):
115 curr = digsig_fitr.Current()
116 result = curr.Verify(opts)
117 if result.GetVerificationStatus():
118 print("Signature verified, objnum: %lu" % curr.GetSDFObj().GetObjNum())
119 else:
120 print("Signature verification failed, objnum: %lu" % curr.GetSDFObj().GetObjNum())
121 verification_status = False
122
123 digest_algorithm = result.GetDigestAlgorithm()
124 if digest_algorithm is DigestAlgorithm.e_SHA1:
125 print("Digest algorithm: SHA-1")
126 elif digest_algorithm is DigestAlgorithm.e_SHA256:
127 print("Digest algorithm: SHA-256")
128 elif digest_algorithm is DigestAlgorithm.e_SHA384:
129 print("Digest algorithm: SHA-384")
130 elif digest_algorithm is DigestAlgorithm.e_SHA512:
131 print("Digest algorithm: SHA-512")
132 elif digest_algorithm is DigestAlgorithm.e_RIPEMD160:
133 print("Digest algorithm: RIPEMD-160")
134 elif digest_algorithm is DigestAlgorithm.e_unknown_digest_algorithm:
135 print("Digest algorithm: unknown")
136 else:
137 assert False, "unrecognized document status"
138
139 print("Detailed verification result: \n\t%s\n\t%s\n\t%s\n\t%s" % (
140 result.GetDocumentStatusAsString(),
141 result.GetDigestStatusAsString(),
142 result.GetTrustStatusAsString(),
143 result.GetPermissionsStatusAsString()))
144
145 changes = result.GetDisallowedChanges()
146 for it2 in changes:
147 print("\tDisallowed change: %s, objnum: %lu" % (it2.GetTypeAsString(), it2.GetObjNum()))
148
149 # Get and print all the detailed trust-related results, if they are available.
150 if result.HasTrustVerificationResult():
151 trust_verification_result = result.GetTrustVerificationResult()
152 print("Trust verified." if trust_verification_result.WasSuccessful() else "Trust not verifiable.")
153 print(trust_verification_result.GetResultString())
154
155 tmp_time_t = trust_verification_result.GetTimeOfTrustVerification()
156
157 trust_verification_time_enum = trust_verification_result.GetTimeOfTrustVerificationEnum()
158
159 if trust_verification_time_enum is VerificationOptions.e_current:
160 print("Trust verification attempted with respect to current time (as epoch time): " + str(tmp_time_t))
161 elif trust_verification_time_enum is VerificationOptions.e_signing:
162 print("Trust verification attempted with respect to signing time (as epoch time): " + str(tmp_time_t))
163 elif trust_verification_time_enum is VerificationOptions.e_timestamp:
164 print("Trust verification attempted with respect to secure embedded timestamp (as epoch time): " + str(tmp_time_t))
165 else:
166 assert False, "unrecognized time enum value"
167
168 if not trust_verification_result.GetCertPath():
169 print("Could not print certificate path.")
170 else:
171 print("Certificate path:")
172 cert_path = trust_verification_result.GetCertPath()
173 for j in range(len(cert_path)):
174 print("\tCertificate:")
175 full_cert = cert_path[j]
176 print("\t\tIssuer names:")
177 issuer_dn = full_cert.GetIssuerField().GetAllAttributesAndValues()
178 for i in range(len(issuer_dn)):
179 print("\t\t\t" + issuer_dn[i].GetStringValue())
180
181 print("\t\tSubject names:")
182 subject_dn = full_cert.GetSubjectField().GetAllAttributesAndValues()
183 for s in subject_dn:
184 print("\t\t\t" + s.GetStringValue())
185
186 print("\t\tExtensions:")
187 for x in full_cert.GetExtensions():
188 print("\t\t\t" + x.ToString())
189
190 else:
191 print("No detailed trust verification result available.")
192
193 unsupported_features = result.GetUnsupportedFeatures()
194 if not unsupported_features:
195 print("Unsupported features:")
196 for unsupported_feature in unsupported_features:
197 print("\t" + unsupported_feature)
198 print("==========")
199
200 digsig_fitr.Next()
201 return verification_status
202
203def CertifyPDF(in_docpath,
204 in_cert_field_name,
205 in_private_key_file_path,
206 in_keyfile_password,
207 in_appearance_image_path,
208 in_outpath):
209
210 print('================================================================================')
211 print('Certifying PDF document')
212
213 # Open an existing PDF
214 doc = PDFDoc(in_docpath)
215
216 if doc.HasSignatures():
217 print('PDFDoc has signatures')
218 else:
219 print('PDFDoc has no signatures')
220
221 page1 = doc.GetPage(1)
222
223 # Create a text field that we can lock using the field permissions feature.
224 annot1 = TextWidget.Create(doc, Rect(143, 440, 350, 460), "asdf_test_field")
225 page1.AnnotPushBack(annot1)
226
227 # Create a new signature form field in the PDFDoc. The name argument is optional;
228 # leaving it empty causes it to be auto-generated. However, you may need the name for later.
229 # Acrobat doesn't show digsigfield in side panel if it's without a widget. Using a
230 # Rect with 0 width and 0 height, or setting the NoPrint/Invisible flags makes it invisible.
231 certification_sig_field = doc.CreateDigitalSignatureField(in_cert_field_name)
232 widgetAnnot = SignatureWidget.Create(doc, Rect(143, 287, 219, 306), certification_sig_field)
233 page1.AnnotPushBack(widgetAnnot)
234
235 # (OPTIONAL) Add an appearance to the signature field.
236 img = Image.Create(doc.GetSDFDoc(), in_appearance_image_path)
237 widgetAnnot.CreateSignatureAppearance(img)
238
239 # Add permissions. Lock the random text field.
240 print('Adding document permissions.')
241 certification_sig_field.SetDocumentPermissions(DigitalSignatureField.e_annotating_formfilling_signing_allowed)
242
243 # Prepare to lock the text field that we created earlier.
244 print('Adding field permissions.')
245 certification_sig_field.SetFieldPermissions(DigitalSignatureField.e_include, ['asdf_test_field'])
246
247 certification_sig_field.CertifyOnNextSave(in_private_key_file_path, in_keyfile_password)
248
249 # (OPTIONAL) Add more information to the signature dictionary.
250 certification_sig_field.SetLocation('Vancouver, BC')
251 certification_sig_field.SetReason('Document certification.')
252 certification_sig_field.SetContactInfo('www.pdftron.com')
253
254 # Save the PDFDoc. Once the method below is called, PDFNet will also sign the document using the information provided.
255 doc.Save(in_outpath, 0)
256
257 print('================================================================================')
258
259def SignPDF(in_docpath,
260 in_approval_field_name,
261 in_private_key_file_path,
262 in_keyfile_password,
263 in_appearance_img_path,
264 in_outpath):
265
266 print('================================================================================')
267 print('Signing PDF document')
268
269 # Open an existing PDF
270 doc = PDFDoc(in_docpath)
271
272 # Retrieve the unsigned approval signature field.
273 found_approval_field = doc.GetField(in_approval_field_name)
274 found_approval_signature_digsig_field = DigitalSignatureField(found_approval_field)
275
276 # (OPTIONAL) Add an appearance to the signature field.
277 img = Image.Create(doc.GetSDFDoc(), in_appearance_img_path)
278 found_approval_signature_widget = SignatureWidget(found_approval_field.GetSDFObj())
279 found_approval_signature_widget.CreateSignatureAppearance(img)
280
281 # Prepare the signature and signature handler for signing.
282 found_approval_signature_digsig_field.SignOnNextSave(in_private_key_file_path, in_keyfile_password)
283
284 # The actual approval signing will be done during the following incremental save operation.
285 doc.Save(in_outpath, SDFDoc.e_incremental)
286
287 print('================================================================================')
288
289def ClearSignature(in_docpath,
290 in_digsig_field_name,
291 in_outpath):
292
293 print('================================================================================')
294 print('Clearing certification signature')
295
296 doc = PDFDoc(in_docpath)
297
298 digsig = DigitalSignatureField(doc.GetField(in_digsig_field_name))
299
300 print('Clearing signature: ' + in_digsig_field_name)
301 digsig.ClearSignature()
302
303 if not digsig.HasCryptographicSignature():
304 print('Cryptographic signature cleared properly.')
305
306 # Save incrementally so as to not invalidate other signatures from previous saves.
307 doc.Save(in_outpath, SDFDoc.e_incremental)
308
309 print('================================================================================')
310
311def PrintSignaturesInfo(in_docpath):
312 print('================================================================================')
313 print('Reading and printing digital signature information')
314
315 doc = PDFDoc(in_docpath)
316 if not doc.HasSignatures():
317 print('Doc has no signatures.')
318 print('================================================================================')
319 return
320 else:
321 print('Doc has signatures.')
322
323 fitr = doc.GetFieldIterator()
324 while fitr.HasNext():
325 current = fitr.Current()
326 if (current.IsLockedByDigitalSignature()):
327 print("==========\nField locked by a digital signature")
328 else:
329 print("==========\nField not locked by a digital signature")
330
331 print('Field name: ' + current.GetName())
332 print('==========')
333
334 fitr.Next()
335
336 print("====================\nNow iterating over digital signatures only.\n====================")
337
338 digsig_fitr = doc.GetDigitalSignatureFieldIterator()
339 while digsig_fitr.HasNext():
340 current = digsig_fitr.Current()
341 print('==========')
342 print('Field name of digital signature: ' + Field(current.GetSDFObj()).GetName())
343
344 digsigfield = current
345 if not digsigfield.HasCryptographicSignature():
346 print("Either digital signature field lacks a digital signature dictionary, " +
347 "or digital signature dictionary lacks a cryptographic Contents entry. " +
348 "Digital signature field is not presently considered signed.\n" +
349 "==========")
350 digsig_fitr.Next()
351 continue
352
353 cert_count = digsigfield.GetCertCount()
354 print('Cert count: ' + str(cert_count))
355 for i in range(cert_count):
356 cert = digsigfield.GetCert(i)
357 print('Cert #' + i + ' size: ' + cert.length)
358
359 subfilter = digsigfield.GetSubFilter()
360
361 print('Subfilter type: ' + str(subfilter))
362
363 if subfilter is not DigitalSignatureField.e_ETSI_RFC3161:
364 print('Signature\'s signer: ' + digsigfield.GetSignatureName())
365
366 signing_time = digsigfield.GetSigningTime()
367 if signing_time.IsValid():
368 print('Signing time is valid.')
369
370 print('Location: ' + digsigfield.GetLocation())
371 print('Reason: ' + digsigfield.GetReason())
372 print('Contact info: ' + digsigfield.GetContactInfo())
373 else:
374 print('SubFilter == e_ETSI_RFC3161 (DocTimeStamp; no signing info)')
375
376 if digsigfield.HasVisibleAppearance():
377 print('Visible')
378 else:
379 print('Not visible')
380
381 digsig_doc_perms = digsigfield.GetDocumentPermissions()
382 locked_fields = digsigfield.GetLockedFields()
383 for it in locked_fields:
384 print('This digital signature locks a field named: ' + it)
385
386 if digsig_doc_perms is DigitalSignatureField.e_no_changes_allowed:
387 print('No changes to the document can be made without invalidating this digital signature.')
388 elif digsig_doc_perms is DigitalSignatureField.e_formfilling_signing_allowed:
389 print('Page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.')
390 elif digsig_doc_perms is DigitalSignatureField.e_annotating_formfilling_signing_allowed:
391 print('Annotating, page template instantiation, form filling, and signing digital signatures are allowed without invalidating this digital signature.')
392 elif digsig_doc_perms is DigitalSignatureField.e_unrestricted:
393 print('Document not restricted by this digital signature.')
394 else:
395 print('Unrecognized digital signature document permission level.')
396 assert(False)
397 print('==========')
398 digsig_fitr.Next()
399
400 print('================================================================================')
401
402def CustomSigningAPI(doc_path,
403 cert_field_name,
404 private_key_file_path,
405 keyfile_password,
406 public_key_file_path,
407 appearance_image_path,
408 digest_algorithm_type,
409 PAdES_signing_mode,
410 output_path):
411 print('================================================================================')
412 print('Custom signing PDF document')
413
414 doc = PDFDoc(doc_path)
415
416 page1 = doc.GetPage(1)
417
418 digsig_field = doc.CreateDigitalSignatureField(cert_field_name)
419 widgetAnnot = SignatureWidget.Create(doc, Rect(143, 287, 219, 306), digsig_field)
420 page1.AnnotPushBack(widgetAnnot)
421
422 # (OPTIONAL) Add an appearance to the signature field.
423 img = Image.Create(doc.GetSDFDoc(), appearance_image_path)
424 widgetAnnot.CreateSignatureAppearance(img)
425
426 # Create a digital signature dictionary inside the digital signature field, in preparation for signing.
427 digsig_field.CreateSigDictForCustomSigning('Adobe.PPKLite',
428 DigitalSignatureField.e_ETSI_CAdES_detached if PAdES_signing_mode else DigitalSignatureField.e_adbe_pkcs7_detached,
429 7500) # For security reasons, set the contents size to a value greater than but as close as possible to the size you expect your final signature to be, in bytes.
430 # ... or, if you want to apply a certification signature, use CreateSigDictForCustomCertification instead.
431
432 # (OPTIONAL) Set the signing time in the signature dictionary, if no secure embedded timestamping support is available from your signing provider.
433 current_date = Date()
434 current_date.SetCurrentTime()
435 digsig_field.SetSigDictTimeOfSigning(current_date)
436
437 doc.Save(output_path, SDFDoc.e_incremental)
438
439 # Digest the relevant bytes of the document in accordance with ByteRanges surrounding the signature.
440 pdf_digest = digsig_field.CalculateDigest(digest_algorithm_type)
441
442 signer_cert = X509Certificate(public_key_file_path)
443
444 # Optionally, you can add a custom signed attribute at this point, such as one of the PAdES ESS attributes.
445 # The function we provide takes care of generating the correct PAdES ESS attribute depending on your digest algorithm.
446 pades_versioned_ess_signing_cert_attribute = DigitalSignatureField.GenerateESSSigningCertPAdESAttribute(signer_cert, digest_algorithm_type)
447
448 # Generate the signedAttrs component of CMS, passing any optional custom signedAttrs (e.g. PAdES ESS).
449 # The signedAttrs are certain attributes that become protected by their inclusion in the signature.
450 signedAttrs = DigitalSignatureField.GenerateCMSSignedAttributes(pdf_digest, pades_versioned_ess_signing_cert_attribute)
451
452 # Calculate the digest of the signedAttrs (i.e. not the PDF digest, this time).
453 signedAttrs_digest = DigestAlgorithm.CalculateDigest(digest_algorithm_type, signedAttrs)
454
455 ############################ custom digest signing starts ############################
456 # At this point, you can sign the digest (for example, with HSM). We use our own SignDigest function instead here as an example,
457 # which you can also use for your purposes if necessary as an alternative to the handler/callback APIs (i.e. Certify/SignOnNextSave).
458 signature_value = DigestAlgorithm.SignDigest(
459 signedAttrs_digest,
460 digest_algorithm_type,
461 private_key_file_path,
462 keyfile_password)
463 ############################ custom digest signing ends ##############################
464
465 # Then, load all your chain certificates into a container of X509Certificate.
466 chain_certs = []
467
468 # Then, create ObjectIdentifiers for the algorithms you have used.
469 # Here we use digest_algorithm_type (SHA256) for hashing, and RSAES-PKCS1-v1_5 (specified in the private key) for signing.
470 digest_algorithm_oid = ObjectIdentifier(ObjectIdentifier.e_SHA256)
471 signature_algorithm_oid = ObjectIdentifier(ObjectIdentifier.e_RSA_encryption_PKCS1)
472
473 # Then, put the CMS signature components together.
474 cms_signature = DigitalSignatureField.GenerateCMSSignature(
475 signer_cert, chain_certs, digest_algorithm_oid, signature_algorithm_oid,
476 signature_value, signedAttrs)
477
478 # Write the signature to the document.
479 doc.SaveCustomSignature(cms_signature, digsig_field, output_path)
480
481 print('================================================================================')
482
483def TimestampAndEnableLTV(in_docpath,
484 in_tsa_url,
485 in_trusted_cert_path,
486 in_appearance_img_path,
487 in_outpath):
488 doc = PDFDoc(in_docpath)
489 doctimestamp_signature_field = doc.CreateDigitalSignatureField()
490 tst_config = TimestampingConfiguration(in_tsa_url)
491 opts = VerificationOptions(VerificationOptions.e_compatibility_and_archiving)
492# It is necessary to add to the VerificationOptions a trusted root certificate corresponding to
493# the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
494# response to be verifiable during DocTimeStamp signing. It is also necessary in the context of this
495# function to do this for the later LTV section, because one needs to be able to verify the DocTimeStamp
496# in order to enable LTV for it, and we re-use the VerificationOptions opts object in that part.
497
498 opts.AddTrustedCertificate(in_trusted_cert_path)
499# By default, we only check online for revocation of certificates using the newer and lighter
500# OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However,
501# it may be necessary to enable online CRL revocation checking in order to verify some timestamps
502# (i.e. those that do not have an OCSP responder URL for all non-trusted certificates).
503
504 opts.EnableOnlineCRLRevocationChecking(True)
505
506 widgetAnnot = SignatureWidget.Create(doc, Rect(0.0, 100.0, 200.0, 150.0), doctimestamp_signature_field)
507 doc.GetPage(1).AnnotPushBack(widgetAnnot)
508
509 # (OPTIONAL) Add an appearance to the signature field.
510 img = Image.Create(doc.GetSDFDoc(), in_appearance_img_path)
511 widgetAnnot.CreateSignatureAppearance(img)
512
513 print('Testing timestamping configuration.')
514 config_result = tst_config.TestConfiguration(opts)
515 if config_result.GetStatus():
516 print('Success: timestamping configuration usable. Attempting to timestamp.')
517 else:
518 # Print details of timestamping failure.
519 print(config_result.GetString())
520 if config_result.HasResponseVerificationResult():
521 tst_result = config_result.GetResponseVerificationResult()
522 print('CMS digest status: '+ tst_result.GetCMSDigestStatusAsString())
523 print('Message digest status: ' + tst_result.GetMessageImprintDigestStatusAsString())
524 print('Trust status: ' + tst_result.GetTrustStatusAsString())
525 return False
526
527
528 doctimestamp_signature_field.TimestampOnNextSave(tst_config, opts)
529
530 # Save/signing throws if timestamping fails.
531 doc.Save(in_outpath, SDFDoc.e_incremental)
532
533 print('Timestamping successful. Adding LTV information for DocTimeStamp signature.')
534
535 # Add LTV information for timestamp signature to document.
536 timestamp_verification_result = doctimestamp_signature_field.Verify(opts)
537 if not doctimestamp_signature_field.EnableLTVOfflineVerification(timestamp_verification_result):
538 print('Could not enable LTV for DocTimeStamp.')
539 return False
540 doc.Save(in_outpath, SDFDoc.e_incremental)
541 print('Added LTV information for DocTimeStamp signature successfully.')
542
543 return True
544
545def main():
546 # Initialize PDFNet
547 PDFNet.Initialize(LicenseKey)
548
549 result = True
550 input_path = '../../TestFiles/'
551 output_path = '../../TestFiles/Output/'
552
553 #################### TEST 0:
554 # Create an approval signature field that we can sign after certifying.
555 # (Must be done before calling CertifyOnNextSave/SignOnNextSave/WithCustomHandler.)
556 # Open an existing PDF
557 try:
558 doc = PDFDoc(input_path + 'waiver.pdf')
559
560 widgetAnnotApproval = SignatureWidget.Create(doc, Rect(300, 287, 376, 306), 'PDFTronApprovalSig')
561 page1 = doc.GetPage(1)
562 page1.AnnotPushBack(widgetAnnotApproval)
563 doc.Save(output_path + 'waiver_withApprovalField_output.pdf', SDFDoc.e_remove_unused)
564 except Exception as e:
565 print(e.args)
566 result = False
567 #################### TEST 1: certify a PDF.
568 try:
569 CertifyPDF(input_path + 'waiver_withApprovalField.pdf',
570 'PDFTronCertificationSig',
571 input_path + 'pdftron.pfx',
572 'password',
573 input_path + 'pdftron.bmp',
574 output_path + 'waiver_withApprovalField_certified_output.pdf')
575 PrintSignaturesInfo(output_path + 'waiver_withApprovalField_certified_output.pdf')
576 except Exception as e:
577 print(e.args)
578 result = False
579 #################### TEST 2: approval-sign an existing, unsigned signature field in a PDF that already has a certified signature field.
580 try:
581 SignPDF(input_path + 'waiver_withApprovalField_certified.pdf',
582 'PDFTronApprovalSig',
583 input_path + 'pdftron.pfx',
584 'password',
585 input_path + 'signature.jpg',
586 output_path + 'waiver_withApprovalField_certified_approved_output.pdf')
587 PrintSignaturesInfo(output_path + 'waiver_withApprovalField_certified_approved_output.pdf')
588 except Exception as e:
589 print(e.args)
590 result = False
591 #################### TEST 3: Clear a certification from a document that is certified and has an approval signature.
592 try:
593 ClearSignature(input_path + 'waiver_withApprovalField_certified_approved.pdf',
594 'PDFTronCertificationSig',
595 output_path + 'waiver_withApprovalField_certified_approved_certcleared_output.pdf')
596 PrintSignaturesInfo(output_path + 'waiver_withApprovalField_certified_approved_certcleared_output.pdf')
597 except Exception as e:
598 print(e.args)
599 result = False
600
601 #################### TEST 4: Verify a document's digital signatures.
602 try:
603 if not VerifyAllAndPrint(input_path + "waiver_withApprovalField_certified_approved.pdf", input_path + "pdftron.cer"):
604 result = False
605 except Exception as e:
606 print(e.args)
607 result = False
608
609 #################### TEST 5: Verify a document's digital signatures in a simple fashion using the document API.
610 try:
611 if not VerifySimple(input_path + 'waiver_withApprovalField_certified_approved.pdf', input_path + 'pdftron.cer'):
612 result = False
613 except Exception as e:
614 print(e.args)
615 result = False
616
617 #################### TEST 6: Custom signing API.
618 # The Apryse custom signing API is a set of APIs related to cryptographic digital signatures
619 # which allows users to customize the process of signing documents. Among other things, this
620 # includes the capability to allow for easy integration of PDF-specific signing-related operations
621 # with access to Hardware Security Module (HSM) tokens/devices, access to cloud keystores, access
622 # to system keystores, etc.
623 try:
624 CustomSigningAPI(input_path + "waiver.pdf",
625 "PDFTronApprovalSig",
626 input_path + "pdftron.pfx",
627 "password",
628 input_path + "pdftron.cer",
629 input_path + "signature.jpg",
630 DigestAlgorithm.e_SHA256,
631 True,
632 output_path + "waiver_custom_signed.pdf")
633 except Exception as e:
634 print(e.args)
635 result = False
636
637 #################### TEST 7: Timestamp a document, then add Long Term Validation (LTV) information for the DocTimeStamp.
638 # try:
639 # # Replace YOUR_URL_OF_TSA with the timestamp authority (TSA) URL to use during timestamping.
640 # # For example, as of July 2024, http://timestamp.globalsign.com/tsa/r6advanced1 was usable.
641 # # Note that this url may not work in the future. A reliable solution requires using your own TSA.
642 # tsa_url = 'YOUR_URL_OF_TSA'
643 # if tsa_url == 'YOUR_URL_OF_TSA':
644 # raise Exception('Error: The URL of your timestamp authority was not specified.')
645 #
646 # # Replace YOUR_CERTIFICATE with the trusted root certificate corresponding to the chain used by the timestamp authority.
647 # # For example, as of July 2024, https://secure.globalsign.com/cacert/gstsacasha384g4.crt was usable.
648 # # Note that this certificate may not work in the future. A reliable solution requires using your own TSA certificate.
649 # trusted_cert_path = 'YOUR_CERTIFICATE'
650 # if trusted_cert_path == 'YOUR_CERTIFICATE':
651 # raise Exception('Error: The path to your timestamp authority trusted root certificate was not specified.')
652 #
653 # if not TimestampAndEnableLTV(input_path + 'waiver.pdf',
654 # tsa_url,
655 # trusted_cert_path,
656 # input_path + 'signature.jpg',
657 # output_path+ 'waiver_DocTimeStamp_LTV.pdf'):
658 # result = False
659 # except Exception as e:
660 # print(e.args)
661 # result = False
662
663 #################### End of tests. #####################
664
665 if not result:
666 print("Tests FAILED!!!\n==========")
667 PDFNet.Terminate()
668 return
669 PDFNet.Terminate()
670 print("Tests successful.\n==========")
671
672if __name__ == '__main__':
673 main()
674# end if __name__ == '__main__'

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales